Chapter 10. Advanced Web Scripts

WHAT'S IN THIS CHAPTER?

  • Internationalizing Web scripts

  • Configuring Web scripts

  • Processing complex HTTP requests

  • Caching Web scripts

  • Setting advanced Descriptor options

The primary design goal of the Web Script Framework is to ensure that simple Web scripts are easy to develop, but advanced Web scripts are still possible. Advanced Web scripts support features such as rendering outputs in multiple languages, exposing and adhering to configuration options, and handling HTML form uploads.

This chapter explores the finer details of the Web Script Framework that allow the development of such advanced features.

INTERNATIONALIZATION

Internationalization (often abbreviated to I18N) is an important consideration when developing any piece of software, and this includes developing a Web script. For human-readable Web script responses it is often necessary to render the output in the preferred language of the user or the preferred language of the client. This means that human-readable text cannot be placed directly in the Web script response template. Therefore, the Web Script Framework employs the common practice of allowing text to be placed into resource bundles, where a resource bundle exists for each supported language.

This is easily demonstrated by creating a simple Web script that renders an HTML message.

  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. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org > example.

  4. You can now create a Web script description document for your I18N sample.

    1. In the Create menu, click Create Content.

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

      i18n.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>I18N Sample</shortname>
         <description>Internationalization Sample</description>
         <url>/i18n</url>
      </webscript>

      Code snippet i18n.get.desc.xml

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  5. Create a default message bundle for your I18N sample.

    1. In the Create menu, click Create Content.

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

      i18n.get.properties
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      greeting=Hello
      farewell=Goodbye

      Code snippet i18n.get.properties

  6. Next, create a response template for your I18N sample.

    1. In the Create menu, click Create Content.

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

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

    4. Click Next.

    5. Type the following in the Enter Content box:

      ${msg("greeting")}. ${msg("farewell")}.

      Code snippet i18n.get.html.ftl

  7. Now register the I18N 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.

The Web script response template uses the msg method to render text whose value is taken from the resource bundle associated with the required language. Resource bundles contain one or more messages, each identified by a name; this is the name passed to the msg method. The example refers to the messages greeting and farewell.

Each resource bundle adheres to the naming convention defined by the Web Script Framework. Resource bundle file names are structured as follows:

<web script id>.<http method>[_<locale>].properties

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 optional <locale> identifies the language for which this resource bundle applies. If not specified, the resource bundle is treated as the fallback set of values if no other relevant resource bundle for the required language can be found.

Finally, all resource bundle file names must end with .properties. This indicates to the Web Script Framework that the file is indeed a resource bundle.

You can now test your response template to ensure it is rendering values from the default resource bundle. To do this, type the following in your command line:

curl "http://localhost:8080/alfresco/service/i18n"

The response is:

Hello. Goodbye.

Now add another resource bundle for the German language.

  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. You can now create a German resource bundle for your I18N sample.

    1. In the Create menu, click Create Content.

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

      i18n.get_de.properties
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      greeting=Guten Tag
      farewell=Auf Wiedersehen

      Code snippet i18n.get_de.properties

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  3. Now re-register the I18N 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.

This time you have created a resource bundle for the German language as identified by the locale of de. Locales are specified as follows:

<language>[_<country>][_<variant>]

The language argument is a valid ISO language code, which is a lowercase, two-letter code as defined by ISO-639. The optional country argument is a valid ISO country code, which is an uppercase, two-letter code as defined by ISO-3166. Finally, the optional variant argument is a vendor-or Web browser–specific code.

Note

The full list of language and country codes can be found at www.ics.uci.edu/pub/ietf/http/related/iso639.txt and www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html.

You can now test your response template to ensure it is rendering values from the German resource bundle. To do this, type the following in your command line:

curl -H "Accept-Language: de" "http://localhost:8080/alfresco/service/i18n"

This results in the following response:

Guten Tag. Auf Wiedersehen.

A client specifies its preferred language through the HTTP header named Accept-Language, which the Web Script Framework adheres to.

Note

A complete definition of the HTTP Accept-Language header can be found at www.w3.org/Protocols/rfc2616/rfc2616-sec14.html.

CONFIGURATION

When developing a Web script, it is sometimes convenient to implement capabilities that provide some flexibility in how they behave. The Web Script Framework supports this by allowing each Web script to carry a configuration file, which the Web script can interrogate in order to alter its behavior.

This is easily demonstrated by creating a Web script whose response is driven by a configuration file.

  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. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org > example.

  4. You can now create a Web script description document for your configuration sample.

    1. In the Create menu, click Create Content.

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

      configuration.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>Configuration Sample</shortname>
        <description>Response driven from configuration</description>
        <url>/config</url>
        <authentication>user</authentication>
      </webscript>

      Code snippet configuration.get.desc.xml

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  5. Create a configuration file for your configuration sample.

    1. In the Create menu, click Create Content.

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

      configuration.get.config.xml
    3. In the Content Type list, select XML.

    4. Click Next.

    5. Type the following in the Enter Content box:

      <greeting>
        <text>Hello</text>
        <repeat>3</repeat>
      </greeting>

      Code snippet configuration.get.config.xml

  6. Next, create a controller script for your configuration sample.

    1. In the Create menu, click Create Content.

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

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

    4. Click Next.

    5. Type the following in the Enter Content box:

      var greeting = new XML(config.script);
      model.repeat = parseInt(greeting.repeat);

      Code snippet configuration.get.js

  7. Create a response template for your configuration sample.

    1. In the Create menu, click Create Content.

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

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

    4. Click Next.

    5. Type the following in the Enter Content box:

      <#list 1..repeat as i>
        ${config.script.greeting.text}
      </#list>

      Code snippet configuration.get.html.ftl

  8. Now register the 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.

The first thing to note is the configuration file name configuration.get.config.xml, which adheres to the naming convention defined by the Web Script Framework. Configuration file names are structured as follows:

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

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 configuration file names must end with .config.xml. This indicates to the Web Script Framework that the file is indeed a configuration file.

Configuration is expressed as any valid XML. In your sample, you specify the greeting text to render and the number of times to repeat the greeting.

Controller scripts access the configuration XML through the root object named config.script. Additionally, E4X, a JavaScript XML API, is used to traverse the XML structure and extract values.

...
var greeting = new XML(config.script);
model.repeat = greeting.repeat;
...

Code snippet configuration.get.js

Your sample extracts the number of times to repeat the greeting from the configuration XML and places the value into the Web script model with the name repeat.

Note

An explanation of how to process XML with E4X can be found at https://developer.mozilla.org/En/E4X/Processing_XML_with_E4X.

Response templates also have access to the configuration XML through the script.config root object. The FreeMarker language supports the traversal of XML, thus allowing response templates to directly extract values from the configuration.

...
${config.script.greeting.text}
...

Code snippet configuration.get.html.ftl

Your sample response template simply extracts the greeting text from the configuration XML and renders it.

Note

A complete guide to processing XML with the FreeMarker language can be found at http://freemarker.org/docs/xgui.html.

You can now test your configuration sample by typing the following in your command line:

curl -uadmin:admin "http://localhost:8080/alfresco/service/config"

This responds with:

Hello
Hello
Hello

Configuration is altered by modifying the configuration XML file, or by creating a new configuration file of the same name in a Web script location that's earlier in the Web Script Framework search path (as described in Chapter 9).

CONTENT NEGOTIATION

Content negotiation is a mechanism defined in the HTTP specification that makes it possible to serve different versions of a document at a given URI, so that a client can specify which version best fits its capabilities. The classic example is for a Web browser to use this mechanism to specify which type of image is preferred, such as GIF or PNG, for display purposes.

As defined in RFC 2616 section 14, a client uses an Accept header to specify a prioritized list of preferred MIME types for the response. When the Web Script Framework receives an HTTP request with an Accept header, it responds with the Web script response format that most closely matches the highest-priority MIME type preference.

Note

RFC 2616 (www.ietf.org/rfc/rfc2616.txt) is the specification for the Hypertext Transfer Protocol – HTTP/1.1.

By default, content negotiation is disabled; however, each Web script may enable content negotiation by declaring its requirements in its descriptor document. This simply involves mapping an incoming Accept header MIME type preference to one of its response formats.

This is best demonstrated by creating a Web script whose response format may be driven by the HTTP Accept header.

  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. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org > example.

  4. You can now create a Web script description document for your content negotiation sample.

    1. In the Create menu, click Create Content.

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

      negotiate.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>Negotiation Sample</shortname>
        <description>Response format driven by content negotiation</description>
      <url>/negotiate</url>
        <negotiate accept="text/html">html</negotiate>
        <negotiate accept="application/json">json</negotiate>
      </webscript>

      Code snippet negotiate.get.desc.xml

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  5. Create an HTML response template for your content negotiation sample.

    1. In the Create menu, click Create Content.

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

      negotiate.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><body>HTML response.</body></html>

      Code snippet negotiate.get.html.ftl

  6. Next, create a JSON response template for your content negotiation sample.

    1. In the Create menu, click Create Content.

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

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

    4. Click Next.

    5. Type the following in the Enter Content box:

      {"response": "json"}

      Code snippet negotiate.get.json.ftl

  7. Now register the 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.

Content negotiation is declared by listing the mappings between an incoming preferred MIME type and a Web script response format. In your sample, the HTML and JSON response formats are mapped to the text/html and application/json MIME types, respectively:

...
<negotiate accept="text/html">html</negotiate>
<negotiate accept="application/json">json</negotiate>
...

Code snippet negotiate.get.desc.xml

You can now test that your sample Web script responds appropriately to content negotiation. First, explicitly request JSON by typing the following in your command line:

curl -H "Accept: application/json" "http://localhost:8080/alfresco/service/
negotiate"

The response is:

{"response": "json"}

Next, you can test to ensure the best response format is chosen. To do this, type the following in your command line:

curl -H "Accept: text/xml,text/*" "http://localhost:8080/alfresco/service/
negotiate"

This time the response is:

<html><body>HTML response.</body></html>

Your sample Web script does not provide an XML response format so cannot respond to the preferred text/xml MIME type; however, it can respond with the HTML response format that matches the second preference of text/*.

MULTIPART FORM PROCESSING

It is common for applications to utilize HTML forms to create and update data and, in particular, for content applications to use forms to upload files from the user's local file system. HTML forms allow data to be submitted in one of two content types: URL-encoded (application-x-www-form-urlencoded) and multipart form data (multipart/form-data).

URL-encoded submissions can be handled by Web scripts in the same manner as other requests, where the Web script can parse the URI to extract the form data. However, the URL-encoded approach is inefficient for sending large quantities of binary data or text containing non-ASCII characters.

To submit forms containing files, non-ASCII, and binary data, the multipart form data content type must be used; however, this type of request is not as simple to parse for the server. Given the common requirement to submit files to the Alfresco content repository, the Web Script Framework provides explicit support for handling multipart form data submissions by hiding the complexity of request parsing from the developer of the Web script.

Note

A complete description of the HTML-form content types can be found at www.w3.org/TR/html401/interact/forms.html#h-17.13.4.

To demonstrate the simplicity of handling multipart/form-data form submits, you will create two Web scripts: one for presenting a form that allows the selection of a file along with title and description, and the other for uploading the selected file into the Alfresco content repository.

  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. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org > example.

  4. You can now create a Web script description document for your form.

    1. In the Create menu, click Create Content.

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

      multipart.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>File Upload Sample</shortname>
        <description>Form to upload file.</description>
        <url>/multipart</url>
        <authentication>user</authentication>
      </webscript>

      Code snippet multipart.get.desc.xml

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  5. Create an HTML response template for your form.

    1. In the Create menu, click Create Content.

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

      multipart.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>
      <body>
        <form action="${url.service}" method="post" enctype="multipart/form-data">
          File: <input type="file" name="file"><br>
          Title: <input name="title"><br>
          Description: <input name="description"><br>
          <input type="submit" name="submit" value="Upload">
        </form>
      </body>
      </html>

      Code snippet multipart.get.html.ftl

  6. Now create a Web script description document for your upload Web script.

    1. In the Create menu, click Create Content.

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

      multipart.post.desc.xml
    3. In the Content Type list, select XML.

    4. Click Next.

    5. Type the following in the Enter Content box:

      <webscript>
        <shortname>File Upload Sample</shortname>
        <description>Handling of multipart/form-data requests.</description>
        <url>/multipart</url>
        <authentication>user</authentication>
      </webscript>

      Code snippet multipart.post.desc.xml

  7. Create a controller script for your upload Web script.

    1. In the Create menu, click Create Content.

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

      multipart.post.js
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      // extract file attributes
      var title = args.title;
      var description = args.description;
      
      // extract file
      var file = null;
      for each (field in formdata.fields)
      {
        if (field.name == "file" && field.isFile)
        {
          file = field;
        }
      }
      
      // ensure file has been uploaded
      if (file.filename == "")
      {
        status.code = 400;
        status.message = "Uploaded file cannot be located";
        status.redirect = true;
      }
      else
      {
        // create document in company home from uploaded file
        upload = companyhome.createFile(file.filename) ;
        upload.properties.content.guessMimetype(file.filename);
        upload.properties.content.write(file.content);
        upload.properties.title = title;
      upload.properties.description = description;
        upload.save();
      
        // setup model for response template
        model.upload = upload;
      }

      Code snippet multipart.post.js

  8. Next, create a response template for your upload Web script.

    1. In the Create menu, click Create Content.

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

      multipart.post.html.ftl
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      <html>
      <body>
        Uploaded ${upload.name} of size ${upload.properties.content.size}.
      </body>
      </html>

      Code snippet multipart.post.html.ftl

  9. Now register the Web scripts 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 are two additional Web scripts.

Your sample form consists of only three input fields, where one is of type file. The form posts its content to the action URI as identified by the root object url.service, which for this sample is /multipart and specifies the multipart/form-data content type.

...
<form action="${url.service}" method="post" enctype="multipart/form-data">
...

Code snippet multipart.get.html.ftl

It is important to note that your two Web scripts are mapped to the same URI. However, the form is attached to the HTTP GET method and the upload is attached to the HTTP POST method, which allows your form to post to the same URI as the form itself.

When multipart/form-data is posted to a Web script, the Web Script Framework provides a special root object named formdata. This root object allows access to the posted request through a simple API, hiding the complexities of parsing the request directly. The API provides access to each form field, including its name and value. For form fields of type file, the content of the uploaded file is also provided. To simplify even further, all fields other than those of type file are also added to the root objects args and argsM.

Your upload Web script extracts the form title and description fields from the args root object and locates the uploaded file through the formdata root object.

...
var title = args.title;
var description = args.description;

var file = null;
for each (field in formdata.fields)
{
  if (field.name == "file" && field.isFile)
  {
    file = field;
  }
}
...

Code snippet multipart.post.js

If a file has been uploaded, the upload Web script creates a new document within the Alfresco content repository under the Company Home folder. The document is named after the file name of the uploaded file and its content is taken from the file content.

...
upload = companyhome.createFile(file.filename) ;
upload.properties.content.guessMimetype(file.filename);
upload.properties.content.write(file.content);
...

Code snippet multipart.post.js

Finally, the created document is placed into the Web script model, allowing the upload response template to render a message confirming the name and size of the uploaded file.

...
model.upload = upload;
...

Code snippet multipart.post.js

It's time to test your upload Web script.

  1. You first need to launch the upload form.

    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/multipart
    2. Fill in the file, title, and description fields of the form and click the Upload button.

    3. If you see a confirmation message detailing the name and size of the uploaded file, your Web script is working.

  2. Now locate the created document in the Alfresco content repository.

    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 the Company Home folder and locate the document whose name matches the uploaded file name.

    3. Examine the properties and content of the created document.

The Form Data API

The Form Data API provides direct access to form fields submitted through the multipart/form-data content type. When requests of this type are posted to a Web script, the Web Script Framework supplies the root object named formdata to the controller script of the Web script.

formdata

formdata is the root object that represents the submitted form, which comprises one or more form fields. Access to the form fields is provided through the following API:

  • hasField(string fieldname)—Returns a Boolean indicating the existence of the form field named fieldname

  • fields—(read-only) An array of formfield objects where each entry represents a field within the form

formfield

The formfield object represents a single field within the form, allowing access to the field metadata and content through the following API:

  • name—(read-only string) The name of the field as defined in the form. Note that form fields may not be uniquely named.

  • isFile—(read-only Boolean) Indicates whether the field is of type file.

  • value—(read-only string) The value of the field as entered into the form. Fields of type file return the file name. File content must be retrieved through content instead.

  • content—(read-only ScriptContent) The value of the field as entered into the form represented as a ScriptContent object whose API is described in Online Appendix D.

  • mimetype—(read-only string) For form fields of type file, the MIME type of the content; otherwise, null.

  • filename—(read-only string) For form fields of type file, the file name of the uploaded file; otherwise, null.

REQUEST PROCESSING

When performing an HTTP POST to a Web script, the posted request body often contains content that needs processing by the Web script. To allow access to the request body, the Web Script Framework provides a special root object named requestbody that represents the content of the request.

The requestbody is a ScriptContent object allowing access to the request content either as a string or as a content stream.

Note

ScriptContent is an object provided with the JavaScript API, which is described in full in Online Appendix D.

Request processing is best demonstrated by creating a Web script, which simply responds with the content of the HTTP request.

  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. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org > example.

  4. You can now create a Web script description document for your request body sample.

    1. In the Create menu, click Create Content.

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

      requestbody.post.desc.xml
    3. In the Content Type list, select XML.

    4. Click Next.

    5. Type the following in the Enter Content box:

      <webscript>
        <shortname>Request Body Sample</shortname>
        <description>Render the request body in the response</description>
        <url>/requestbody</url>
        <authentication>user</authentication>
      </webscript>

      Code snippet requestbody.post.desc.xml

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  5. Create a controller script for your request body sample.

    1. In the Create menu, click Create Content.

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

      requestbody.post.js
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      model.requestcontent = requestbody.content;

      Code snippet requestbody.post.js

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  6. Next, create an HTML response template for your request body sample.

    1. In the Create menu, click Create Content.

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

      requestbody.post.html.ftl
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      ${requestcontent}

      Code snippet requestbody.post.html.ftl

  7. Now register the 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 an additional Web script.

Your example consists of just two lines of code. The controller script extracts the request content from the requestbody root object and places it into the Web script model under the name requestcontent. The response template simply outputs the model value into the response.

You can test this Web script with cURL by typing the following in your command line:

curl -uadmin:admin -H "Content-Type: application/json" --data-binary "{"request":
"body"}" "http://localhost:8080/alfresco/service/requestbody"

This posts a request body of {"request": "body"} to your Web script, which in turn responds with:

{"request": "body"}

Often the content posted in a request is structured using data formats such as XML or JSON, which the Web script has to parse. Parser code is generally painful to develop, so the Web Script Framework provides a mechanism known as a Format Reader that parses a request of a given MIME type into an object that represents the request content. The object is then supplied to the controller script, which can interrogate the object to extract request content.

The Web Script Framework provides the following out-of-the-box Format Readers:

  • JSON: Parses a request of MIME type application/json into a root object named json

  • Atom Feed: Parses a request of MIME type application/atom+xml;type=feed into a root object named feed whose type is an Apache Abdera Feed object

  • Atom Entry: Parses a request of MIME type application/atom+xml;type=entry into a root object named entry whose type is an Apache Abdera Entry object

  • Atom: Parses a request of MIME type application/atom+xml into a root object named either feed (Apache Abdera Feed) or entry (Apache Abdera Entry), depending on the request content

Note

Apache Abdera is an open source implementation of the Atom Syndication Format (RFC 4287) and the Atom Publishing Protocol (RFC 5023).

You can now extend your request processing Web script example by adding a new controller script that uses the json root object provided by the Web Script Framework.

  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. You can now create the additional controller script document for your request body sample.

    1. In the Create menu, click Create Content.

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

      requestbody.post.json.js
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      model.requestcontent = json.get("request");

      Code snippet requestbody.post.json.js

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  3. Now re-register the 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.

Format Readers are not invoked automatically. You have to ask the Web Script Framework to convert the response and provide the resulting object to the controller script. This is achieved by creating a controller script with an alternate naming convention:

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

The difference here is that the controller script file name also contains the <format> segment, indicating to the Web Script Framework that requests of the specified format are handled by this controller and require the converted root object.

In the example, you create a new controller script named requestbody.post.json.js to handle JSON posted requests. This controller now has access to the json root object, as provided by the JSON Format Reader, and can extract values directly from the JSON document.

...
model.requestcontent = json.get("request");
...

Code snippet requestbody.post.json.js

You can test the updated Web script with cURL by typing the following in your command line:

curl -uadmin:admin -H "Content-Type: application/json" --data-binary
"{"request": "body"}" "http://localhost:8080/alfresco/service/requestbody"

This posts a request body of {"request": "body"} to your Web script, which in turn responds with:

body

Instead of echoing the complete request as before, the updated controller script extracts the value named request from the JSON document and places it into the Web script model, which in this case is the value body.

The JSON Object API

The JSON Object API provides the ability to programmatically traverse JSON documents, where the root of the document is either a JSON array or a JSON object.

The Web Script Framework, if instructed, supplies a root object named json to the Web script, which is one of the following object types, depending on the root of the JSON document.

JSONArray

The JSONArray object type represents an array within a JSON document and provides the following API:

  • length()—(read-only integer) Returns the length of the JSON array

  • getJSONObject(integer index)—Returns the JSON object located in the JSON array at the specified index

JSONObject

The JSONObject object type represents an object within a JSON document and provides the following API:

  • get(string name): Returns the value of the specified name from the JSON object

  • has(string name): Indicates whether the value of the specified name exists within the JSON object

  • isNull(string name): Indicates whether the value of the specified name is null within the JSON object

  • getJSONArray(string name): Returns a JSONArray object for the array of the specified name within the JSON object

CACHING

A key aspect of HTTP is its ability to support caching of HTTP responses, relieving workload on the HTTP server, which does not have to re-create the HTTP response for every request. From a client perspective this gives a prompt response.

The Web Script Framework complies with HTTP caching, in particular with the notions of Last Modified Time and ETag (a kind of hash), allowing the caching of Web script responses using HTTP-aware caches.

Note

An ETag (entity tag) is a response header and is used to determine change in content at a given URL. Clients and caches use the ETag in subsequent requests to determine with the server if the content needs refreshing.

As a developer of a Web script you may specify its caching requirements, such as how long to keep the response in the cache or how to calculate the hash for the response. It's important to note that the Web Script Framework does not actually perform any caching. Alfresco decided that it is better to rely on one of the many HTTP caches already available, such as Squid (www.squid-cache.org), an HTTP caching proxy. Therefore, it is necessary to either embed an HTTP cache in your client or deploy an HTTP-cache proxy in front of the Alfresco Content Application Server to enable caching.

Descriptor Cache Controls

When developing a Web script, it is possible through the Web script descriptor document to specify whether its response is to be cached and, if so, how it is to be cached.

The optional <cache> element of the Web script descriptor provides the following cache flags:

  • never (optional) specifies whether caching should be applied at all. If true, the Web script response should never be cached; otherwise, the Web script response may be cached.

  • public (optional) specifies whether authenticated responses should be cached in a public cache. If true, the Web script response should never be cached; otherwise, the Web script response may be cached.

  • mustrevalidate (optional) specifies whether a cache must revalidate its version of the Web script response in order to ensure freshness. If true, the cache must revalidate; otherwise, the cache may revalidate.

For example, the following Web script descriptor specifies that responses may be cached, but never in a public cache as the response requires authentication, and that the cache must revalidate to ensure freshness of the content.

<webscript>
  <shortname>Design time cache sample</shortname>
  <url>/cache</url>
  <authentication>user</authentication>
  <cache>
     <never>false</never>
     <public>false</public>
     <mustrevalidate/>
   </cache>
</webscript>

Runtime Cache Controls

Some cache controls can be set only during the execution of a Web script, such as setting when the content of the response was last modified. To support this, the Web Script Framework provides a special root object named cache to all controller scripts for allowing cache controls to be set at runtime.

The cache root object provides the following API:

  • 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 descriptor.

  • 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 descriptor.

  • 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 descriptor.

  • 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.

Cache controls are best demonstrated by creating a sample Web script which sets the last modified date.

  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. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org > example.

  4. You can now create a Web script description document for your cache sample.

    1. In the Create menu, click Create Content.

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

      cache.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>Cache example</shortname>
         <description>Demonstrate cache controls</description>
         <url>/cache</url>
         <authentication>user</authentication>
         <cache>
           <never>false</never>
           <mustrevalidate/>
         </cache>
      </webscript>

      Code snippet cache.get.desc.xml

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  5. Create a controller script for your cache sample.

    1. In the Create menu, click Create Content.

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

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

    4. Click Next.

    5. Type the following in the Enter Content box:

      cache.lastModified = new Date();

      Code snippet cache.get.js

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  6. Next, create an HTML response template for your cache sample.

    1. In the Create menu, click Create Content.

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

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

    4. Click Next.

    5. Type the following in the Enter Content box:

      Cached response.

      Code snippet cache.get.html.ftl

  7. Now register the 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 an additional Web script.

Remember, the Web Script Framework does not perform any caching of its own. It ensures correct HTTP headers are transmitted based on the Web script cache controls for an external cache to interpret.

When testing cache controls, it is useful to test with cURL, as this gives you access to the headers sent on the HTTP response. For example, to test your cache sample, type the following in your command line:

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

The returned response is similar to the following, where the Cache-Control and Last-Modified headers are present:

* 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/cache HTTP/1.1
> Authorization: Basic YWRtaW46YWRtaW4=
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Cache-Control:  must-revalidate
< Last-Modified: Tue, 02 Feb 2010 09:07:05 GMT
< Content-Type: text/html;charset=UTF-8
< Content-Length: 16
< Date: Tue, 02 Feb 2010 09:07:05 GMT

Caching is an important aspect of Web scripts and is often required in order to support high-load applications such as Internet Web sites backed by the Alfresco Content Application Server. As such, caching should be considered when developing all Web scripts.

ADVANCED DESCRIPTOR OPTIONS

The following Web script descriptor options are not essential, but provide useful capabilities on those rare occasions they are needed.

Lifecycle

The lifecycle option allows a Web script developer to indicate the development status of a Web script. Typically, Web scripts start out in a draft state while being developed or tested, are then promoted to production quality for widespread use, and are finally retired at the end of their life.

The following lifecycle values are available:

  • none indicates that this Web script is not part of a lifecycle.

  • sample indicates that this Web script is a sample and is not intended for production use.

  • draft indicates that this Web script may be incomplete, experimental, or still subject to change.

  • public_api indicates that this Web script is part of a public API and should be stable and well tested.

  • draft_public_api indicates that this Web script is intended to become part of the public API but is incomplete or still subject to change.

  • deprecated indicates that this Web script should be avoided; it may be removed in future versions of the product.

  • internal indicates that this Web script is for Alfresco use only; it should not be relied upon between versions and is likely to change.

An example usage of the lifecycle option follows:

<webscript>
  <shortname>Example Lifecycle Usage</shortname>
  <url>/lifecycle</url>
  <lifecycle>sample</lifecycle>
</webscript>

Family

The family option allows a Web script developer to categorize their Web scripts. Any value may be assigned to family and any number of families may be assigned to the Web script, providing a free-form tagging mechanism. The Web script index provides views for navigating Web scripts by family.

Note

The Web script index is provided at http://localhost:8080/alfresco/service/ on the machine on which you installed Alfresco.

An example usage of the family option follows:

<webscript>
  <shortname>Example Family Usage</shortname>
  <url>/family</url>
  <family>CMIS</family>
  <family>Dashlet</family>
</webscript>

Run As

The Run As option allows a Web script developer to state that the execution of a Web script must run as a particular Alfresco content repository user regardless of who initiated the Web script.

This is useful in scenarios where the behavior of the Web script requires specific permissions to succeed. Due to security concerns, the Run As option is only available for Web script implementations that are placed into the Java classpath.

The user to run as is specified through the runas attribute of the <authentication> element of the Web script descriptor, as demonstrated in the following:

<webscript>
  <shortname>Example Run As Usage</shortname>
  <url>/runas</url>
  <authentication runas="admin">user</authentication>
</webscript>

Here the Web script still requires a user to authenticate before execution; however, the Web script executes as the admin user. Content repository features such as auditing still reflect the user who initiated the Web script.

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

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