This page presents some sample Web Scripts that reside in your Alfresco Server at the folder:
/Company Home/Data Dictionary/Web Scripts/org/alfresco/sample
You can run some of these scripts right now on a clean install of Alfresco 2.1 or later.
If you installed by following Installing on Microsoft Windows or Linux Quick Install then you can access the folder webscript here:
http://localhost:8080/alfresco/service/sample/folder/Company%20Home
Log in with the username admin and password admin.
For each Sample described below, you see the following information:
Description Document
Execute Script
Response Template
These are source of the content items in Alfresco, found by browsing to the following space:
Company Home > Data Dictionary > Web Scripts > org > alfresco > sample
The file names and extensions are important as they tell Alfresco what the item is for.
If you want to experiment with your first web script see this page: Web Scripts Hello World Quick Start
This sample very simply demonstrates how to create a polite Alfresco Repository.
GET /alfresco/service/sample/hello
Examples:
http://<host>:<port>/alfresco/service/sample/hello
File: hello.get.desc.xml
<webscript> <shortname>Hello</shortname> <description>Polite greeting</description> <url>/sample/hello</url> <authentication>user</authentication> </webscript>
File: hello.get.html.ftl
Hello ${person.properties.userName}.
This sample demonstrates how to implement a URL service that renders the contents of a folder in either HTML or ATOM. The HTML rendition allows for the browsing of a folder hierarchy.
GET /alfresco/service/sample/folder/{path}
Examples:
http://<host>:<port>/alfresco/service/sample/folder/Company%20Home http://<host>:<port>/alfresco/service/sample/folder/Company%20Home?format=atom
File: folder.get.desc.xml
<webscript> <shortname>Folder Listing Sample</shortname> <description>Sample demonstrating the listing of folder contents</description> <url>/sample/folder/{path}</url> <format default="html">argument</format> <authentication>guest</authentication> <transaction>required</transaction> </webscript>
File: folder.get.js
// locate folder by path var folder = roothome.childByNamePath(url.extension); if (folder == undefined || !folder.isContainer) { status.code = 404; status.message = "Folder " + url.extension + " not found."; status.redirect = true; } model.folder = folder;
File: folder.get.html.ftl
<html> <head> <title>${folder.displayPath}/${folder.name}</title> </head> <body> Folder: ${folder.displayPath}/${folder.name} <br> <table> <#if folder.parent.parent?exists> <tr> <td><td><a href="${url.serviceContext}/sample/folder<@encodepath node=folder.parent/>">..</a> </tr> </#if> <#list folder.children as child> <tr> <#if child.isContainer> <td>><td><a href="${url.serviceContext}/sample/folder<@encodepath node=child/>">${child.name}</a> <#else> <td><td><a href="${url.serviceContext}/api/node/content/${child.nodeRef.storeRef.protocol}/${child.nodeRef.storeRef.identifier}/${child.nodeRef.id}/${child.name?url}">${child.name}</a> </#if> </tr> </#list> </table> </body> </html> <#macro encodepath node><#if node.parent?exists><@encodepath node=node.parent/>/${node.name?url}</#if></#macro>
File: folder.get.atom.ftl
<?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <generator version="${server.version}">Alfresco (${server.edition})</generator> <title>Folder: ${folder.displayPath}/${folder.name}</title> <updated>${xmldate(date)}</updated> <icon>${absurl(url.context)}/images/logo/AlfrescoLogo16.ico</icon> <#list folder.children as child> <entry> <title>${child.name}</title> <#if child.isContainer> <link rel="alternate" href="${absurl(url.serviceContext)}/sample/folder<@encodepath node=child/>"/> <#else> <link rel="alternate" href="${absurl(url.serviceContext)}/api/node/content/${child.nodeRef.storeRef.protocol}/${child.nodeRef.storeRef.identifier}/${child.nodeRef.id}/${child.name?url}"/> </#if> <icon>${absurl(url.context)}${child.icon16}</icon> <id>urn:uuid:${child.id}</id> <updated>${xmldate(child.properties.modified)}</updated> <summary>${child.properties.description!""}</summary> <author> <name>${child.properties.creator}</name> </author> </entry> </#list> </feed> <#macro encodepath node><#if node.parent?exists><@encodepath node=node.parent/>/${node.name?url}</#if></#macro>
Warning: AVM Deprecation |
This sample (split into two web scripts) demonstrates how to browse WCM/AVM stores.
This sample demonstrates how to implement a URL service that renders a list of all AVM stores.
GET /alfresco/service/sample/avm/stores
Examples:
http://<host>:<port>/alfresco/service/sample/avm/stores
File: avmstores.get.desc.xml
<webscript> <shortname>AVM Stores Sample</shortname> <description>Sample demonstrating the listing of AVM stores</description> <url>/sample/avm/stores</url> <format default="html"/> <authentication>admin</authentication> <transaction>required</transaction> </webscript>
File: avmstores.get.html.ftl
<html> <head> <title>AVM Stores</title> </head> <body> AVM Stores <br> <br> <table> <tr> <#list avm.stores as store> <tr> <td>${store.creator}<td> <td>${store.createdDate?datetime}<td> <td><a href="${url.serviceContext}/sample/avm/path/${store.id}/">${store.id} </tr> </#list> </table> </body> </html>
This sample demonstrates how to implement a URL service that renders the contents of an AVM folder in HTML. The rendition allows for the browsing of a folder hierarchy.
GET /alfresco/service/sample/avm/path/{storeid}/{path}
Examples:
http://<host>:<port>/alfresco/service/sample/avm/path/main--admin/www
File: avmbrowse.get.desc.xml
<webscript> <shortname>AVM Browse Sample</shortname> <description>Sample demonstrating the listing of AVM folder contents</description> <url>/sample/avm/path/{storeid}/{path}</url> <format default="html">argument</format> <authentication>admin</authentication> <transaction>required</transaction> </webscript>
File: avmbrowse.get.js
script: { // extract avm store id and path var fullpath = url.extension.split("/"); if (fullpath.length == 0) { status.code = 400; status.message = "Store id has not been provided."; status.redirect = true; break script; } var storeid = fullpath[0]; var path = (fullpath.length == 1 ? "/" : "/" + fullpath.slice(1).join("/")); // locate avm node from path var store = avm.lookupStore(storeid); if (store == undefined) { status.code = 404; status.message = "Store " + storeid + " not found."; status.redirect = true; break script; } var node = avm.lookupNode(storeid + ":" + path); if (node == undefined) { status.code = 404; status.message = "Path " + path + " within store " + storeid + " not found."; status.redirect = true; break script; } // setup model for templates model.store = store; model.folder = node; }
File: avmbrowse.get.html.ftl
<html> <head> <title>AVM Folder: ${folder.displayPath}/${folder.name}</title> </head> <body> <a href="${url.serviceContext}/sample/avm/stores">AVM Store</a>: ${store.id} <br> <br> AVM Folder: ${folder.displayPath}/${folder.name} <br> <br> <table> <#if folder.parent?exists> <tr> <td>${folder.parent.properties.creator}<td> <td>${folder.parent.size}<td> <td>${folder.parent.properties.modified?datetime}<td> <td><td><a href="${url.serviceContext}/sample/avm/path/${store.id}<@encodepath node=folder.parent/>">..</a> </tr> </#if> <#list folder.children as child> <tr> <#if child.isContainer> <td>${child.properties.creator}<td> <td>${child.size}<td> <td>${child.properties.modified?datetime}<td> <td>><td><a href="${url.serviceContext}/sample/avm/path/${store.id}<@encodepath node=child/>">${child.name}</a> <#else> <td>${child.properties.creator}<td> <td>${child.size}<td> <td>${child.properties.modified?datetime}<td> <td><td><a href="${url.serviceContext}/api/node/content/${child.nodeRef.storeRef.protocol}/${child.nodeRef.storeRef.identifier}/${child.nodeRef.id}/${child.name?url}">${child.name}</a> </#if> </tr> </#list> </table> </body> </html>
This sample demonstrates how to implement a URL service that performs a full-text search whose results are rendered in either HTML or ATOM.
GET /alfresco/service/sample/blog/search?q={searchTerm}
Examples:
http://<host>:<port>/alfresco/service/sample/blog/search?q=alfresco http://<host>:<port>/alfresco/service/sample/blog/search.atom?q=alfresco
File: blogsearch.get.desc.xml
<webscript> <shortname>Blog Search Sample</shortname> <description>Sample that finds all blog entries whose content contains the specified search term</description> <url>/sample/blog/search?q={searchTerm}</url> <url>/sample/blog/search.atom?q={searchTerm}</url> <url>/sample/b/s?q={searchTerm}</url> <url>/sample/b/s.atom?q={searchTerm}</url> <format default="html">extension</format> <authentication>guest</authentication> <transaction>required</transaction> </webscript>
File: blogsearch.get.js
// check that search term has been provided if (args.q == undefined || args.q.length == 0) { status.code = 400; status.message = "Search term has not been provided."; status.redirect = true; } else { // perform search var nodes = search.luceneSearch("TEXT:" + args.q); model.resultset = nodes; }
NOTE: The above script executes a simple full-text search across the whole repository. It could be extended to search within a specific folder or a specific type of content.
File: blogsearch.get.html.ftl
<html> <body> <img src="${url.context}/images/logo/AlfrescoLogo32.png" alt="Alfresco" /> Blog query: ${args.q} <br> <table> <#list resultset as node> <tr> <td><img src="${url.context}${node.icon16}"/> <td><a href="${url.serviceContext}/api/node/content/${node.nodeRef.storeRef.protocol}/${node.nodeRef.storeRef.identifier}/${node.nodeRef.id}/${node.name?url}">${node.name}</a> </tr> </#list> </table> </body> </html>
File: blogsearch.get.atom.ftl
<?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <generator version="${server.version}">Alfresco (${server.edition})</generator> <title>Blog query: ${args.q}</title> <updated>${xmldate(date)}</updated> <icon>${absurl(url.context)}/images/logo/AlfrescoLogo16.ico</icon> <#list resultset as node> <entry> <title>${node.name}</title> <link rel="alternate" href="${absurl(url.serviceContext)}/api/node/content/${node.nodeRef.storeRef.protocol}/${node.nodeRef.storeRef.identifier}/${node.nodeRef.id}/${node.name?url}"/> <icon>${absurl(url.context)}${node.icon16}</icon> <id>urn:uuid:${node.id}</id> <updated>${xmldate(node.properties.modified)}</updated> <summary>${node.properties.description!""}</summary> <author> <name>${node.properties.creator}</name> </author> </entry> </#list> </feed>
File: blogsearch.get.html.404.ftl
<html> <body> ${status.message} </body> </html>
File: blogsearch.get.atom.404.ftl
<?xml version="1.0" encoding="UTF-8"?> <response> ${status.code}
<codeName>${status.codeName}</codeName> <codeDescription>${status.codeDescription}</codeDescription> <message>${status.message}</message> </response>
This sample demonstrates how to implement a URL service that performs a category search whose results are rendered in either HTML or ATOM.
Content may be categorized via the Alfresco Web Client (Content Properties page).
GET /alfresco/service/sample/blog/category/{category}
Examples:
http://<host>:<port>/alfresco/service/sample/blog/category/EUROPE
File: categorysearch.get.desc.xml
<webscript> <shortname>Category Search</shortname> <description>Find all blog entries tagged with specified categories</description> <url>/sample/blog/category/{category}</url> <format default="html">extension</format> <authentication>guest</authentication> <transaction>required</transaction> </webscript>
File: categorysearch.get.js
// check category exists? var category = search.luceneSearch("PATH:\"/cm:generalclassifiable//cm:" + url.extension + "\""); if (category == undefined) { status.code = 404; status.message = "Category " + url.extension + " not found."; status.redirect = true; } else { // perform category search var nodes = search.luceneSearch("PATH:\"/cm:generalclassifiable//cm:" + url.extension + "//member\""); model.resultset = nodes; }
NOTE: The above script executes a simple category search across the whole repository. It could be extended to search within a specific folder or a specific type of content.
File: categorysearch.get.html.ftl
<html> <body> <img src="${url.context}/images/logo/AlfrescoLogo32.png" alt="Alfresco" /> Category search: ${url.extension} <br> <table> <#list resultset as node> <tr> <td><img src="${url.context}${node.icon16}"/> <td><a href="${url.serviceContext}/api/node/content/${node.nodeRef.storeRef.protocol}/${node.nodeRef.storeRef.identifier}/${node.nodeRef.id}/${node.name?url}">${node.name}</a> </tr> </#list> </table> </body> </html>
File: categorysearch.get.atom.ftl
<?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <generator version="${server.version}">Alfresco (${server.edition})</generator> <title>Category search: ${url.extension}</title> <updated>${xmldate(date)}</updated> <icon>${absurl(url.context)}/images/logo/AlfrescoLogo16.ico</icon> <#list resultset as node> <entry> <title>${node.name}</title> <link rel="alternate" href="${absurl(url.serviceContext)}/api/node/content/${node.nodeRef.storeRef.protocol}/${node.nodeRef.storeRef.identifier}/${node.nodeRef.id}/${node.name?url}"/> <icon>${absurl(url.context)}${node.icon16}</icon> <id>urn:uuid:${node.id}</id> <updated>${xmldate(node.properties.modified)}</updated> <summary>${node.properties.description!""}</summary> <author> <name>${node.properties.creator}</name> </author> </entry> </#list> </feed>
File: categorysearch.get.html.404.ftl
<html> <body> ${status.message} </body> </html>
File: categorysearch.get.atom.404.ftl
<?xml version="1.0" encoding="UTF-8"?> <response> <code>${status.code}</code> <codeName>${status.codeName}</codeName> <codeDescription>${status.codeDescription}</codeDescription> <message>${status.message}</message> </response>
This sample (split into two web scripts) demonstrates how to implement a file upload URL service.
The first web script presents a simple HTML form with three form fields, one of which is of type file
. The form POSTs to a second web script which parses the posted multipart/form-data request and creates a new file in the repository using the values entered into the form.
GET /sample/upload
File: upload.get.desc.xml
<webscript> <shortname>File Upload Form Sample</shortname> <description>Form for uploading file content and meta-data into Repository</description> <url>/sample/upload</url> <authentication>user</authentication> </webscript>
File: upload.get.html.ftl
<html> <head> <title>Upload Web Script Sample</title> <link rel="stylesheet" href="${url.context}/css/main.css" TYPE="text/css"> </head> <body> <table> <tr> <td><img src="${url.context}/images/logo/AlfrescoLogo32.png" alt="Alfresco" /></td> <td><nobr>Upload Web Script Sample</nobr></td> </tr> <tr><td><td>Alfresco ${server.edition} v${server.version} </table> <p> <table> <form action="${url.service}" method="post" enctype="multipart/form-data" accept-charset="utf-8"> <tr><td>File:</td><td><input type="file" name="file"></td></tr> <tr><td>Title:</td><td><input name="title"></td></tr> <tr><td>Description:</td><td><input name="desc"></td></tr> <tr><td></td></tr> <tr><td><input type="submit" name="submit" value="Upload"></td></tr> </form> </table> </body> </html>
POST /sample/upload
File: upload.post.desc.xml
<webscript> <shortname>File Upload Sample</shortname> <description>Upload file content and meta-data into Repository</description> <url>/sample/upload</url> <authentication>user</authentication> </webscript>
File: upload.post.js
var filename = null; var content = null; var title = ""; var description = ""; // locate file attributes for each (field in formdata.fields) { if (field.name == "title") { title = field.value; } else if (field.name == "desc") { description = field.value; } else if (field.name == "file" && field.isFile) { filename = field.filename; content = field.content; } } // ensure mandatory file attributes have been located if (filename == undefined || content == undefined) { status.code = 400; status.message = "Uploaded file cannot be located in request"; status.redirect = true; } else { // create document in company home for uploaded file upload = companyhome.createFile("upload" + companyhome.children.length + "_" + filename) ; upload.properties.content.write(content); upload.properties.content.setEncoding("UTF-8"); upload.properties.content.guessMimetype(filename); upload.properties.title = title; upload.properties.description = description; upload.save(); // setup model for response template model.upload = upload; }
File: upload.post.html.ftl
<html> <head> <title>Upload Web Script Sample</title> <link rel="stylesheet" href="${url.context}/css/main.css" TYPE="text/css"> </head> <body> <table> <tr> <td><img src="${url.context}/images/logo/AlfrescoLogo32.png" alt="Alfresco" /></td> <td><nobr>Upload Web Script Sample</nobr></td> </tr> <tr><td>Alfresco ${server.edition} v${server.version}</td></tr> <tr><td></td></tr> <tr><td>Uploaded <a href="${url.serviceContext}/sample/folder${upload.displayPath}">${upload.name}</a> of size ${upload.properties.content.size}.</td></tr> </table> </body> </html>
This sample demonstrates how to process URL arguments (single and multi-valued).
GET /alfresco/service/sample/args
Examples:
http://<host>:<port>/alfresco/service/args?a=2&a=1&b=3
File: args.get.desc.xml
<webscript> <shortname>Argument Handling Sample</shortname> <description>Demonstrate access to single and multi-valued arguments</description> <url>/sample/args</url> <authentication>none</authentication> </webscript>
File: args.get.js
// log each argument (assuming only one value has been provided for each) for (arg in args) { logger.log(arg + "=" + args[arg]); } // log each argument (assuming one or more values have been provided for each) for (arg in argsM) { for each (val in argsM[arg]) { logger.log(arg + "=" + val); } }
File: args.get.html.ftl
<#list args?keys as arg> ${arg}=${args[arg]} </#list> <#list argsM?keys as arg> <#list argsM[arg] as val> ${arg}=${val} </#list> </#list>
This sample demonstrates how to specify Cache control at definition-time and run-time. (sorry, available 2.1 Enterprise onwards)
GET /alfresco/service/sample/cache
Examples:
http://<host>:<port>/alfresco/service/sample/cache
File: cache.get.desc.xml
<webscript> <shortname>Cache Sample</shortname> <description>Demonstrates how to control caching for a Web Script</description> <url>/sample/cache</url> <authentication>guest</authentication> <format default="text"/> <cache> <never>false</never> <public/> </cache> </webscript>
File: cache.get.js
var tutorial = companyhome.childByNamePath("/Guest Home/Alfresco-Tutorial.pdf"); model.tutorial = tutorial; cache.ETag = tutorial.properties.description; cache.lastModified = tutorial.properties.modified;
File: cache.get.text.ftl
${tutorial.properties.description}
To effectively speed up webscripts execution through caching one, at least, needs to:
The new response may be different because the webscript code has changed or the data managed by the webscript have changed.
This Caching Alfresco Webscripts article explains how to implement these and other requirements. A reusableworking example is supplied to ease experimentation.
This sample demonstrates how to support redirection for the 3xx family of status codes. (available in 2.1.2 Enterprise onwards)
GET /alfresco/service/sample/location
Examples:
http://<host>:<port>/alfresco/service/sample/location
File: location.get.desc.xml
<webscript> <shortname>Status Location</shortname> <description>Demonstrates how to handle 3xx redirection status codes</description> <url>/sample/3xxLocation</url> <authentication>none</authentication> </webscript>
File: location.get.js
status.code = 307; // Temporary redirect status.location = url.service + "/temp";
File: location.get.html.ftl
This resource you're looking for is at <a href="${status.location}">${status.location}</a>.
This functionality will not have any user interface in 2.1, but you can execute a very simple JavaScript via URL to set a web script as a nifty custom view for a space:
// example script to set the Document List webscript as the custom view for a node // @param noderef space to set webscript against as custom view var dest = search.findNode("<noderef>"); dest.addAspect("cm:webscriptable"); dest.properties["cm:webscript"] = "/service/ui/doclist?q=*"; dest.save();
You may wish to pass context to your web script to inform it which space or document it is processing against. This can be done as follows:
// example script to set the Document List webscript as the custom view for a node // @param noderef space to set webscript against as custom view var dest = search.findNode("<noderef>"); dest.addAspect("cm:webscriptable"); dest.properties["cm:webscript"] = "/service/ui/doclist?nodeRef={noderef}"; dest.save();
Your web script will now receive an argument with the name nodeRef
whose value is the node reference of the space or document to which the web script is being applied. The following code demonstrates how you can use this argument within your web script to retrieve the node:
<#assign nodeRef = args["nodeRef"]> <#assign node = companyhome.nodeByReference[nodeRef]>
Your web script can then proceed to business as usual with code like:
The name of this space is ${node.name}
and so forth.
If you want to generate JSON output in your templates you can do it using Spring's helper Json classes in your freemarker template.
For example:
<#escape x as jsonUtils.encodeJSONString(x)> { "Results" : [ <#list data as item> {"label":"${item.label}", "value":"${item.value}"}, </#list> ] } </#escape>
See this page for how to easily create dialogs displaying web scripts. Using this mechanism, the creation of a dialog is only the definition of a corresponding well-configured action.
A Wiki page is available that documents several Java-backed Web Scripts Samples which were developed during the Alfresco Barcelona Community Conference in 2008. This covers the concepts as well as development and code. It provides a link to an AMP file that you can use to quickly see how these are put together and deployed.