Chapter 11. Java-Backed Web Scripts

WHAT'S IN THIS CHAPTER?

  • Understanding Java-backed Web scripts

  • Implementing a Java Folder Listing Web script

  • Creating a new kind of Web script

In this chapter, you will discover how to develop Java-backed Web scripts, which are Web scripts whose controller implementation is written in Java, rather than JavaScript. You might be wondering why you would need to dive into Java, when JavaScript Web scripts seem to cater to most requirements. Although rare, Java-backed Web scripts are useful when:

  • Accessing Alfresco Content Application Services not available via the JavaScript API

  • Interacting with systems whose only API is exposed via Java

  • Overriding how responses are rendered, such as to stream large content

  • Performance is absolutely critical

Unlike scripted Web scripts, Java-backed Web scripts require more tooling for their development. The Java source code has to be compiled, then packaged, and finally deployed to the Alfresco Content Application Server. This means deeper knowledge of the Alfresco architecture is required, such as knowing how Alfresco employs the Spring Framework for registering and binding together Java components.

Although this seems daunting, it's not that different from developing a scripted Web script, especially if you're already familiar with Java. A Java-backed Web script (as shown in Figure 11-1) has a very similar construction to that of a scripted Web script.

FIGURE 11-1

Figure 11.1. FIGURE 11-1

The primary difference is that a Java class replaces the controller script. It still has the same intent of encapsulating the behavior of the Web script and producing a model for subsequent rendering by a response template. Alfresco is aware of the Java class through Spring Framework configuration, which identifies the Java class as being the behavior for the Web script. All other components are exactly the same as those for scripted Web scripts.

Note

The Spring Framework is an open source application framework for the Java platform best known for providing an Inversion of Control container, Aspect-Oriented Programming, and abstractions for data access and transaction management. Led and sustained by SpringSource, full details of the Spring Framework can be found at www.springsource.org.

STEP-BY-STEP: FOLDER LISTING JAVA-BACKED WEB SCRIPT

Java-backed Web scripts are best illustrated by developing an example. In this case, you are going to build the equivalent of the Folder ListingWeb script that was introduced in Chapter 9. This Web script mimics the behavior of the 'dir' command in Microsoft Windows, or 'ls' in Linux and Mac OS X.

Although the implementation introduced in this chapter replaces the controller script with Java, the behavior will not change: users will perceive no difference. In fact, it doesn't matter how theWeb script is implemented, as the client only interacts with it through HTTP requests and responses. This is very useful as it is sometimes convenient and efficient to build a library of scripted Web scripts exposing a well-defined interface and then, over time, replace their implementation with Java, if requirements such as performance become critical. As long as the interface does not change, the user will not notice.

Get started by first creating the scripted components of your 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. 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. Now create a Web script description document for your Java 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:

      javadir.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>Java-backed implementation of listing folder contents
      </description>
        <url>/javadir/{folderpath}?verbose={verbose?}</url>
        <authentication>user</authentication>
      </webscript>

      Code snippet javadir.get.desc.xml

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  5. Create a Web script response template for your Java 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:

      javadir.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 javadir.get.html.ftl

    6. Click Next.

    7. Click Finish.

    8. Click OK.

The Web script description specifies a URI template containing the tokens {folderpath} and {verbose?}. The folderpath token represents the folder to list and the verbose URI argument specifies whether a verbose listing is required or not.

The HTML response template renders the contents of the specified folder, taking into account the verbose flag. It does this by accessing the Web script model values named folder and verbose.

You haven't yet completed your Web script, which is still missing its controller. In this case, the controller needs to parse the URI to extract the token values, interact with the Alfresco content repository to locate the specified folder, and populate the model for subsequent rendering by the HTML response template.

It's now time to switch to Java for developing your controller.

  1. First, create the Java class for your Folder Listing Web script.

    1. Launch your Java IDE.

    2. Create a Java package whose name is:

      org.example
    3. Create a Java class whose name is:

      JavaDir
    4. Implement the Java class as follows:

      package org.example;
      
      import java.util.HashMap;
      import java.util.Map;
      
      import org.alfresco.repo.model.Repository;
      import org.alfresco.service.cmr.repository.NodeRef;
      import org.alfresco.web.scripts.Cache;
      import org.alfresco.web.scripts.DeclarativeWebScript;
      import org.alfresco.web.scripts.Status;
      import org.alfresco.web.scripts.WebScriptException;
      import org.alfresco.web.scripts.WebScriptRequest;
      
      public class JavaDir extends DeclarativeWebScript
      {
          private Repository repository;
      
          public void setRepository(Repository repository)
          {
              this.repository = repository;
          }
      
          protected Map<String, Object> executeImpl(WebScriptRequest req,
              Status status, Cache cache)
          {
              // extract folder listing arguments from URI
              String verboseArg = req.getParameter("verbose");
              Boolean verbose = Boolean.parseBoolean(verboseArg);
              Map<String, String> templateArgs =
                req.getServiceMatch().getTemplateVars();
              String folderPath = templateArgs.get("folderpath");
      // search for folder within Alfresco content repository
              String nodePath = "workspace/SpacesStore/" + folderPath;
              NodeRef folder = repository.findNodeRef("path", nodePath.split("/"));
      
              // validate that folder has been found
              if (folder == null)
              {
                  throw new WebScriptException(Status.STATUS_NOT_FOUND,
                    "Folder " + folderPath + " not found");
              }
      
              // construct model for response template to render
              Map<String, Object> model = new HashMap<String, Object>();
              model.put("verbose", verbose);
              model.put("folder", folder);
              return model;
          }
      }

      Code snippet JavaDir.java

    5. Compile the Java class.

    6. Place the compiled Java class into the folder org/example within the Web application classpath of the Alfresco Content Application Server.

  2. Next, create the Spring Framework configuration for registering your Web script Java class.

    1. Create an XML file whose name is:

      javadir-context.xml
    2. Register the Java class as follows:

      <?xml version='1.0' encoding='UTF-8'?>
      <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN 2.0//EN'
        'http://www.springframework.org/dtd/spring-beans-2.0.dtd'>
      
      <beans>
        <bean id="webscript.org.example.javadir.get"
              class="org.example.JavaDir" parent="webscript">
          <property name="repository" ref="repositoryHelper"/>
        </bean>
      </beans>

      Code snippet javadir-context.xml

    3. Place the Spring Framework configuration file into the extension classpath of the Alfresco Content Application Server.

Note

The Java samples in this chapter depend on the following libraries: alfresco-core, alfresco-repository, alfresco-webscript-framework, and dom4j.

Note

For a default installation of Alfresco, the web application classpath is located at installLocation/tomcat/webapps/alfresco/WEB-INF/classes and the extension classpath is located at installLocation/tomcat/shared/classes/alfresco/extension.

When deploying a Java-backed Web script to the Alfresco Content Application Server, the server must be restarted for it to be fully registered.

You can now test your Java-backed Web script. In your Web browser, type the following:

http://localhost:8080/alfresco/service/javadir/Company%20Home?verbose=true

If successful, you will see a verbose listing of the contents of the Company Home folder. Externally, this Folder Listing Web script looks and behaves the same as its scripted Web script implementation.

JAVA APPROACH TO WEB SCRIPTS

The Java class for a Java-backed Web script only has to follow one rule, which is that it implements the Java interface:

org.alfresco.web.scripts.WebScript

This interface defines the following two methods, which must be implemented:

/**
 * Gets the Web script Description
 *
 * @return the Web script description
 */
public WebScriptDescription getDescription();

/**
 * Execute the Web script
 *
 * @param req  the Web script request
 * @param res  the Web script response
 */
public void execute(WebScriptRequest req, WebScriptResponse res) throws
IOException;

The first method, getDescription(), returns a WebScriptDescription object, which is a Java representation of the Web script description XML document. The second method, execute(), is invoked by the Web Script Framework to initiate the Web script.

Thankfully, the Web Script Framework also provides two Java classes that implement the difficult parts of this interface, which you can extend as a starting point. The simplest helper Java class is named as follows:

org.alfresco.web.scripts.AbstractWebScript

This helper provides an implementation of getDescription() but does not provide any execution assistance, which it delegates to its derived class. This allows a Java-backed Web script to take full control of the execution process, including how output is rendered to the response.

The other helper Java class is named as follows:

org.alfresco.web.scripts.DeclarativeWebScript

This helper provides an implementation of getDescription() and execute(). Interestingly, it encapsulates the execution of a scripted Web script, which is:

  • Locate an associated controller script written in JavaScript and, if found, execute it.

  • Locate an associated response template for the requested format and execute it, passing the model populated by the controller script.

By default, all Web scripts implemented through scripting alone are actually backed by the DeclarativeWebScript Java class. There is one special hook point, though, that makes this a very useful class for your own Java-backed Web scripts to extend. Just prior to controller script execution, DeclarativeWebScript invokes the template method executeImpl(), which it expects derived Java classes to implement.

protected Map<String, Object> executeImpl(WebScriptRequest req, Status status,
    Cache cache)

This is where the behavior of a custom Java-backed Web script is encapsulated, including the population of the Web script model, which is returned from this method.

Your Java Folder Listing Web script uses DeclarativeWebScript for its starting point.

...
public class JavaDir extends DeclarativeWebScript
{
  ...
  protected Map<String, Object> executeImpl(WebScriptRequest req, Status status,
      Cache cache)
  {
    ...
    return model;
  }
  ...
}

Code snippet JavaDir.java

The model returned from executeImpl() is passed to the response template for subsequent rendering. Prior to template rendering, the model may also be accessed and further refined by a controller script, if one happens to be provided for the Web script.

Apart from implementing the WebScript interface, there are no other Web script demands on the Java class. You are free to give the Java class any name and place it in any Java package.

Parsing the URI

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

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

To extract the values provided for the {folderpath} and {verbose} tokens, the following Java code is used:

...
String verboseArg = req.getParameter("verbose");
Boolean verbose = Boolean.parseBoolean(verboseArg);
Map<String, String> templateArgs = req.getServiceMatch().getTemplateVars();
String folderPath = templateArgs.get("folderpath");
...

Code snippet JavaDir.java

Access to the request that invoked the Web script is through the req parameter of the executeImpl() method. This parameter encapsulates everything about the request, including its URI, query parameters, and header values. In particular, the getParameter() method of the request provides access to query parameters, which your Web script uses to retrieve the value of the verbose flag. If the query parameter is not specified on the URI, the returned value is null.

Access to tokens specified in the URI path is also through the req parameter. A map of all URI-path token values indexed by token name is provided by req.getServiceMatch().getTemplateVars(). Your Web script uses this map to retrieve the value of the folderpath token. URI-path token values are never null.

Imagine a client has made the following URI request:

/javadir/Company%20Home?verbose=true

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

Calling Alfresco Services

As a Java-backed Web script, all services provided by the Alfresco Content Application Server are available for use. In fact, any Java API within the server process, subject to security controls, is accessible.

Access to services is provided through a mechanism known as Dependency Injection (DI). Instead of the Java-backed Web script locating its dependent services, the dependent services are handed to the Web script.

Note

Dependency Injection is a technique for supplying an external dependency to a software component. A full description of this technique can be found at http://en.wikipedia.org/wiki/Dependency_injection.

Alfresco employs the Spring Framework for its Dependency Injection capabilities. This means that dependencies are specified in a separate XML configuration file as part of the Java-backed Web script registration. This XML configuration will be covered in more detail later in this chapter.

How are dependent services actually injected? For each dependency, the Java-backed Web script provides a setter method for accepting a reference to the dependent service. The Spring Framework invokes each of the setter methods with the appropriate configured dependency during the initialization of the Java-backed Web script. By the time the Web script is executed, all dependent services are available within the executeImpl() method.

Your Folder Listing Web script needs to locate the folder within the Alfresco content repository that is identified by the folderpath token. To accomplish this, the Web script injects a Repository service that provides some simple content repository access capabilities.

...
public class JavaDir extends DeclarativeWebScript
{
    private Repository repository;

    public void setRepository(Repository repository)
    {
        this.repository = repository;
    }

    protected Map<String, Object> executeImpl(WebScriptRequest req,
        Status status, Cache cache)
    {
        ...
        String nodePath = "workspace/SpacesStore/" + folderPath;
        NodeRef folder = repository.findNodeRef("path", nodePath.split("/"));
        ...
    }
}

Code snippet JavaDir.java

The setRepository method represents the setter method that is called by the Spring Framework. Its implementation simply stores the Repository service reference in a member variable of the Java-backed Web script for subsequent access in the executeImpl() method.

Setting the Response Status Code

A Web script uses a response status code to inform the calling client of its execution outcome. In Java, exceptions are often used for this and Java-backed Web scripts may follow suit.

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

...
if (folder == null)
{
    throw new WebScriptException(Status.STATUS_NOT_FOUND,
      "Folder " + folderPath + " not found");
}
...

Code snippet JavaDir.java

The WebScriptException class is a special kind of exception supported by the Web Script Framework, which carries a status code and message. Whenever a Web script throws this kind of exception, the Web Script Framework translates it into the equivalent status on the HTTP response.

All other exceptions are caught by the Web Script Framework and translated into the 500 status code, which means an internal error occurred. In all cases, the status response template has access to details such as the status code, status message, and exception call stack.

Throwing an exception is not always ideal, so the Web Script Framework provides another approach to setting the response status code. The executeImpl() method is passed a Status object, which allows the Web script to set the status explicitly.

Your Folder Listing Web script can implement folder validation using the following alternate code:

...
if (folder == null)
{
   status.setCode(Status.SC_NOT_FOUND);
   status.setMessage("Folder " + folderPath + " not found");
   status.setRedirect(true);
   return;
}
...

One advantage of setting the status explicitly is that the Web script may control whether a status response template is used to render the status through the setRedirect() method.

Exceptions may be handled in a similar manner:

...
catch(ConstraintException e)
{
   status.setCode(Status.SC_FORBIDDEN);
   status.setMessage("Cannot create folder");
   status.setException(e);
   status.setRedirect(true);
}
...

The setException() method allows the Web script to associate the status with the caught exception.

Constructing the Model

One of the responsibilities of the controller is to create a model for subsequent rendering by a response template. A model is a map of values indexed by name. In Java, the model is simply returned from the executeImpl() method as a Map.

Your Folder Listing Web script constructs a HashMap and places the verbose flag and located folder into it.

...
Map<String, Object> model = new HashMap<String, Object>();
model.put("verbose", verbose);
model.put("folder", folder);
return model;
...

Code snippet JavaDir.java

The model is then subsequently available to response templates, which can use the values to render the output. An important point is that values placed into the map by Java are converted to values that are accessible to the FreeMarker template language.

For example, your Java Folder Listing Web script places a NodeRef into the model under the name folder, which it received from the Repository service. A NodeRef represents a reference to an object residing in the content repository. The Web Script Framework converts NodeRefs into full objects so that FreeMarker templates can easily reference their object properties and methods as demonstrated by your Folder Listing response template:

Contents of folder ${folder.displayPath}/${folder.name}

Code snippet javadir.get.html.ftl

A Java-backed Web script does not have to create a model. In this case, the executeImpl() method can simply return null.

SPRING-FRAMEWORK REGISTRATION

A Java-backed Web script must be registered with the Web Script Framework. This is done through Spring Framework configuration, which supports the notion of a bean: a declaration of a Java class instance.

Each Java-backed Web script is defined by its own bean declaration. For example, your Java Folder Listing Web script is declared as follows:

...
<beans>
  ...
  <bean id="webscript.org.example.javadir.get"
      class="org.example.JavaDir" parent="webscript">
    ...
  </bean>
  ...
</beans>

Code snippet javadir-context.xml

Spring beans are given a unique identifier through their id attribute and construct an instance of the Java class as named through their class attribute.

The Web Script Framework uses the following bean id naming convention for locating Java-backed Web scripts:

webscript.<web script package>.<web script id>.<http method>

The <web script package>, <web script id>, and <http method> are used to bind the Java class to the associated Web script. The class attribute simply refers to the Java class implementing the Java-backed Web script.

Finally, all Web script bean declarations must have the parent 'webscript'.

Service Dependencies

The Spring bean is also the place where service dependencies are declared. Your Folder Listing Web script declares a single dependency on the Repository service as follows:

...
<bean id="webscript.org.example.javadir.get"
      class="org.example.JavaDir" parent="webscript">
   <property name="repository" ref="repositoryHelper"/>
</bean>
...

Code snippet javadir-context.xml

Each dependency is represented by a <property> element whose name attribute identifies the setter method to call and whose ref attribute identifies the service to depend on. The ref value is actually an ID of another bean. All Alfresco services are declared as beans, so can be injected in this way.

In the example, repository maps to the setRepository() method and repositoryHelper maps to the bean representing the Repository service.

...
public class JavaDir extends DeclarativeWebScript
{
   ...
   public void setRepository(Repository repository)
   {
      ...
   }
}

Code snippet JavaDir.java

Although your example only declares a single dependency, multiple dependencies may be declared. The Spring Framework calls setter methods during the initialization of the Java-backed Web script, so all dependencies are resolved by the time the executeImpl() is invoked.

CREATING A NEW KIND OF WEB SCRIPT

On some occasions it is useful to extend the capabilities of the Web Script Framework by introducing a new kind of Web script. This is useful for encapsulating behavior that you wish to reuse across many scripted Web scripts.

This is best demonstrated by developing a new kind of Web script. Your example will encapsulate the logic for finding a node in the content repository given a node path and placing that node into the Web script model. Web scripts of this kind only have to declaratively specify the node path in their Web script description for the model to be automatically populated with the associated node.

Behavior for a new kind of Web script is encapsulated in Java; therefore, you can follow the same steps as for developing a Java-backed Web script.

Time to get started.

  1. First, create the Java class for your new kind of Web script.

    1. Launch your Java IDE.

    2. Create a Java package whose name is:

      org.example
    3. Create a Java class whose name is:

      NodeWebScript
    4. Implement the Java class as follows:

      package org.example;
      
      import java.io.Serializable;
      import java.util.HashMap;
      import java.util.Map;
      import org.alfresco.repo.model.Repository;
      import org.alfresco.service.cmr.repository.NodeRef;
      import org.alfresco.web.scripts.Cache;
      import org.alfresco.web.scripts.DeclarativeWebScript;
      import org.alfresco.web.scripts.Status;
      import org.alfresco.web.scripts.WebScriptException;
      import org.alfresco.web.scripts.WebScriptRequest;
      
      public class NodeWebScript extends DeclarativeWebScript
      {
          private Repository repository;
      
          public void setRepository(Repository repository)
          {
              this.repository = repository;
          }
      
          protected Map<String, Object> executeImpl(WebScriptRequest req,
              Status status, Cache cache)
          {
              // extract node path from description extensions
              Map<String, Serializable> extensions =
                getDescription().getExtensions();
              String path = (String)extensions.get("path");
      
              // search for folder within Alfresco content repository
              String nodePath = "workspace/SpacesStore/" + path;
              NodeRef node = repository.findNodeRef("path", nodePath.split("/"));
      
              // validate that node has been found
              if (node == null)
              {
                  throw new WebScriptException(Status.STATUS_NOT_FOUND,
                    "Path " + path + " not found");
              }
      
              // construct model for response template to render
              Map<String, Object> model = new HashMap<String, Object>();
              model.put("node", node);
              return model;
          }
      }

      Code snippet NodeWebScript.java

    5. Compile the Java class.

    6. Place the compiled Java class into the folder org/example within the Web application classpath of the Alfresco Content Application Server.

  2. Next, create a Java class for extracting the node path configuration for your new kind of Web script.

    1. Create a Java class in the package org.example whose name is:

      NodeWebScriptExtension
    2. Implement the Java class as follows:

      package org.example;
      
      import java.io.InputStream;
      import java.io.Serializable;
      import java.util.HashMap;
      import java.util.Map;
      
      import org.alfresco.web.scripts.DescriptionExtension;
      import org.alfresco.web.scripts.WebScriptException;
      import org.dom4j.Document;
      import org.dom4j.DocumentException;
      import org.dom4j.Element;
      import org.dom4j.io.SAXReader;
      
      public class NodeWebScriptExtension implements DescriptionExtension
      {
          public Map<String, Serializable> parseExtensions(String serviceDescPath,
              InputStream servicedesc)
          {
              Map<String, Serializable> extensions =
                new HashMap<String, Serializable>();
              SAXReader reader = new SAXReader();
              try
              {
                  // extract path value from description document
                  Document document = reader.read(servicedesc);
                  Element rootElement = document.getRootElement();
                  Element pathElement = rootElement.element("path");
                  String path = pathElement.getTextTrim();
                  extensions.put("path", path);
              }
              catch (DocumentException e)
              {
                  throw new WebScriptException("Failed to parse", e);
              }
              return extensions;
          }
      }

      Code snippet NodeWebScriptExtension.java

    3. Compile the Java class.

    4. Place the compiled Java class into the folder org/example within the Web application classpath of the Alfresco Content Application Server.

  3. Now create the Spring Framework configuration file for registering your new kind of Web script.

    1. Create an XML file whose name is:

      nodewebscript-context.xml
    2. Register the Java classes as follows:

      <?xml version='1.0' encoding='UTF-8'?>
      <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN 2.0//EN'
      'http://www.springframework.org/dtd/spring-beans-2.0.dtd'>
      
      <beans>
      
        <bean id="webscript.org.example.nodewebscript"
              class="org.example.NodeWebScript" parent="webscript"
              scope="prototype">
          <property name="repository" ref="repositoryHelper"/>
        </bean>
      
        <bean id="webscriptdesc.org.example.nodewebscript"
              class="org.example.NodeWebScriptExtension"/>
      
      </beans>

      Code snippet nodewebscript-context.xml

    3. Place the Spring Framework configuration into the extension classpath of the Alfresco Content Application Server.

Your example Java class extends DeclarativeWebScript just like other Java-backed Web scripts. Its primary purpose is to locate a node in the Alfresco content repository given a node path, which it does using the Repository service. The NodeRef returned from the Repository service is placed into the Web script model under the name node.

How does the implementation get hold of the node path? Instead of parsing the URI, the example uses a Web script description extension, which allows custom information to be placed into the Web script description. In this case, the path is to be extracted from a <path> element as follows:

<webscript>
  ...
  <path>Company Home/Data Dictionary</path>
  ...
</webscript>

Extensions to the Web script description are accessed through the getDescription().getExtensions() method, which returns a map of extension values indexed by name. Your example extracts the path as follows:

...
Map<String, Serializable> extensions = getDescription().getExtensions();
String path = (String)extensions.get("path");
...

Code snippet NodeWebScript.java

The extension map still needs to be created from the Web script description XML document. This requires the development of another Java class that implements the following interface:

org.alfresco.web.scripts.DescriptionExtension

This interface defines the following single method, which must be implemented:

/**
 * Parse Web script description extensions
 *
 * @param serviceDescPath  path to service document
 * @param serviceDesc  service document input stream
 * @return extensions mapped by name
 */
public Map<String, Serializable> parseExtensions(String serviceDescPath,
   InputStream servicedesc);

An implementation of this interface parses the Web script description document to extract the custom extensions and returns a map of those extensions indexed by name. This is the same map that is returned by getDescription().getExtensions().

Your example extracts the value of the <path> element from the Web script description document and places it into the extension map under the name path.

...
// extract path value from description document
Document document = reader.read(servicedesc);
Element rootElement = document.getRootElement();
Element pathElement = rootElement.element("path");
String path = pathElement.getTextTrim();
extensions.put("path", path);
...

Code snippet NodeWebScriptExtension.java

Finally, both Java classes are registered as Spring beans whose identifiers follow the naming convention defined by the Web Script Framework.

...
<bean id="webscript.org.example.nodewebscript"
      class="org.example.NodeWebScript" parent="webscript"
      scope="prototype">
  ...
</bean>

<bean id="webscriptdesc.org.example.nodewebscript"
      class="org.example.NodeWebScriptExtension"/>
...

Code snippet nodewebscript-context.xml

The Web script Java class identifier is structured as follows:

webscript.<web script kind id>

whereas the Web script description extension Java class identifier is structured as follows:

webscriptdesc.<web script kind id>

The <web script kind id> can be any unique value but both IDs must match each other to be tied together.

Using a New Kind of Web Script

When developing a scripted Web script, it is possible to specify its kind through its Web script description document. If the new kind of Web script supports extensions to the Web script description document, then those must be provided as well. Otherwise, development of the Web script is the same as any other Web script.

You will implement a simple Web script based on the example NodeWebScript kind, which simply renders information about the Data Dictionary folder held in 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 now create a Web script description document for your Data Dictionary information sample.

    1. In the Create menu, click Create Content.

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

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

    4. Click Next.

    5. Type the following in the Enter Content box:

      <webscript kind="org.example.nodewebscript">
        <shortname>Node Info</shortname>
        <description>Demonstration of Web script Kind</description>
        <url>/info</url>
        <authentication>user</authentication>
        <path>Company Home/Data Dictionary</path>
      </webscript>

      Code snippet info.get.desc.xml

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  5. Create a response template for your Data Dictionary information sample.

    1. In the Create menu, click Create Content.

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

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

    4. Click Next.

    5. Type the following in the Enter Content box:

      ${node.name} created on ${node.properties.created?date}

      Code snippet info.get.html.ftl

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  6. Now register the Data Dictionary Information 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.

  7. Finally, it's time to 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/info
    2. If you see a message similar to Data Dictionary created on Jan 12, 2010, your Web script is working.

The Web script kind is specified through the kind attribute of the <webscript> element contained within the Web script description document. Its value is the <web script kind id> as defined in the Spring configuration for the new kind of Web script.

In your example, the NodeWebScript kind is selected by specifying its identifier of org.example.nodewebscript:

<webscript kind="org.example.nodewebscript">
  ...
  <path>Company Home/Data Dictionary</path>
  ...
</webscript>

Code snippet info.get.desc.xml

As expected by the NodeWebScript, the description document also specifies a path to a node in the Alfresco content repository. In the example, you specify the Data Dictionary folder through the custom <path> element.

Your example does not provide a controller script, as the NodeWebScript Java class already encapsulates the behavior of locating a node given a path and populating the Web script model. In this case, the located node is placed into the Web script model under the name node.

${node.name} created on ${node.properties.created?date}

Code snippet info.get.html.ftl

This means the response template can simply refer to node to render the output.

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

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