In an earlier chapter on web forms, we talked about how we can use Alfresco WCM for content production. Now in this section, we will discuss some of the case studies where the actual application is outside of Alfresco, but the content will be stored in Alfresco WCM and needs to be served from Alfresco only. For that, we can use Alfresco web scripts, which will act as an integration point for Alfresco WCM content and the actual application.
Let's consider the case where we want to have a news portlet in some Liferay Portal Application. So here, rendering of the portlet will be handled in Liferay, but the actual news content and the headlines for the news are stored in Alfresco WCM.
We have some news content stored in the /ROOT/common/inc
folder, and we will try to fetch the headlines for these news items.
In this example, we will create a web script for fetching the news headlines from Alfresco. We will use JavaScript as the controller and will return the response in XML format. This XML response will then be processed by a portlet in Liferay and the final news headline will be displayed on the news portlet.
The description document, getNewsHeadline.get.desc.xml
, which describes the URL and the authentication mechanism for the web script is as follows:
<webscript> <shortname>Listing Of News Headlines</shortname> <description>Listing Of News Headlines for Cignex home page thru Webscript</description> <url>/org/cignex/news/getNewsHeadlines.xml?storeId={storeId}</url> <authentication>user</authentication> </webscript>
JavaScript controller, getNewsHeadline.get.js
, executes the search query to fetch the news items' nodes from the WCM repository. This is done using the Lucene Search API to search the content of a specific web form. Here in this example, it's the news web form. Keep in mind that this Lucene Search will only be applied to the Staging Sandbox of a web project. Here we have storeId
as one of the web script parameters, but that should point to the Staging Sandbox of a web project:
var storeId = args["storeId"]; var newsNodes = new Array(); if(storeId != null) { var webProjectStore = avm.lookupStore(storeId); if(webProjectStore != null) { var queryForNews = "@wca\:parentformname:news AND @cm\:name:"*.xml""; var resultNodes = webProjectStore.luceneSearch(queryForNews); if(resultNodes != null) { logger.log("Reslut nodes: " + resultNodes.length); for (var i=0; i<resultNodes.length; i++) { newsNodes[i] = resultNodes[i]; } } } if(newsNodes != null) { model.m_newsNodes=newsNodes; } } else{ logger.log("ERROR: 'store' argument not specified."); }
The rendering template for the XML response, getNewsHeading.xml.ftl
file, is as follows:
<#ftl ns_prefixes={"D", "http://www.alfrescobook.com/webforms"}> <news> <#if m_newsNodes?exists> <#list m_newsNodes as newsNode> <#assign newsItemDom = newsNode.xmlNodeModel/> <#if newsItemDom?exists> <#assign newsItem = newsItemDom.news> <#if newsItem?exists> <newsItem> <newsId>${newsNode.name</newsId> <title><! [CDATA[${newsItem.shortTitle}]]></title> <header><! [CDATA[${newsItem.contentHeader}]]></header> <date>${newsItem.newsDate}</date> </newsItem> </#if> </#if> </#list> </#if> </news>
Once done with the development of a web script with all of the three mentioned files, we need to store it in an appropriate place. Let's store it through Alfresco Explorer. We will store the web script files in the Company Home | Data Dictionary | Web Scripts Extensions folder.
Create the folder structure as org/cignex/news
inside the Web Scripts Extensions folder and upload all of the three web script-related files here, as mentioned in a previous section on storing a web script. After uploading, you should see all of the three files in the news folder, as shown in the next screenshot:
Once done with this, register the web scripts by navigating to http://localhost:8080/alfresco/service/index
and clicking on the Refresh Web Scripts button as mentioned before in the section on registering a web script. Now that the new web script is registered, we can start using it with the URL. If you want to check it, you can click on any of the browse options. Clicking on Browse by Web Script URI will browse all of the web scripts' URI. By doing so, you can verify your web script is there. Now we will see how to use this web script in Liferay.
Now in Liferay, you need to create a new portlet and call our web script from that portlet. The following screenshot shows a snap of a portal page where one of the portlets is News & Press. The content of this portlet is fetched from the Alfresco WCM:
You can download the code samples for web script-related files and the news portlet .war
file for Liferay from the Packt website.
In this case study, we will see the integration between Alfresco WCM and Drupal. This will be an integration of two different technologies, Java and PHP. We are going to take an example from monthly blogs. As in Chapter 4, Web Content Production with Web Forms, we have a web form for creating different blog items in the WCM. So we do have some blog items available with us in the WCM, which we will display on a Drupal page.
Here we will have a web script that will fetch the blog content from Alfresco WCM for a particular month based on the published date of the blog content. We will use JavaScript as a controller and will return the response in HTML format. So in Drupal, we do not need to do any complex processing; just display the HTML as it is.
The description document, getMonthlyBlogs.get.desc.xml
, which describes the URL and the authentication mechanism for the web script is as follows:
<webscript> <shortname>Listing Of Blogs</shortname> <description>Listing Of Blogs for Cignex home page thru Webscript </description> <url>/org/cignex/blogs/getBlogs.xml?storeId={storeId}&month= {monthnumber}</url> <authentication>user</authentication> </webscript>
The JavaScript controller, getMonthlyBlogs.get.js
, executes the search query to fetch the blog items' nodes from the WCM repository. This is done using the Lucene Search API to search the contents of a specific web form; here it's the blog's web form. Keep in mind that this Lucene Search will only be applied to the Staging Sandbox of a web project. Here we have storeId
as one of the web script parameters, but that should point to the Staging Sandbox of a web project:
var storeId = args["storeId"]; var blogNodes = new Array(); if(storeId != null) { var webProjectStore = avm.lookupStore(storeId); if(webProjectStore != null) { var queryForBlogs = "@wca\:parentformname:blog AND @cm\:name:"*.xml""; var resultNodes = webProjectStore.luceneSearch(queryForBlogs); if(resultNodes != null) { logger.log("Result nodes: " + resultNodes.length); for (var i=0; i<resultNodes.length; i++) { blogNodes[i] = resultNodes[i]; } } } if(blogNodes != null) { model.m_blogNodes=blogNodes; } } else{ logger.log("ERROR: 'store' argument not specified."); }
The rendering template for the HTML response, getMonthlyBlogs.get.html.ftl
file, is as follows:
<#ftl ns_prefixes={"D", "http://www.alfrescobook.com/webforms"}> <#if args["month"]?exists> <#assign monthnumber=args["month"]> <#else> <#assign dateformat="yyyy-MM-dd"> <#assign monthnumber=date?string(dateformat)?substring(5,7)> </#if> <#switch monthnumber> <#case '1'> <#assign month="January"> <#break> <#case '2'> <#assign month="Febuary"> <#break> <#case '3'> <#assign month="March"> <#break> <#case '4'> <#assign month="April"> <#break> <#case '5'> <#assign month="May"> <#break> <#case '6'> <#assign month="June"> <#break> <#case '7'> <#assign month="July"> <#break> <#case '8'> <#assign month="August"> <#break> <#case '9'> <#assign month="September"> <#break> <#case '10'> <#assign month="October"> <#break> <#case '11'> <#assign month="November"> <#break> <#case '12'> <#assign month="December"> <#break> </#switch> <html> <body> <#if m_blogNodes?exists> <font face="Verdana" color="CC3333"> <h3>Blogs for Month - ${month} </h3> </font> <table width="100%" cellspacing="0" cellpadding="0" border="0"> <#list m_blogNodes as blogNode> <#assign blogItemDom = blogNode.xmlNodeModel/> <#if blogItemDom?exists> <#assign blogItem = blogItemDom.blog> <#if blogItem?exists> <#if blogItem.publishedDate?substring(5,7) == monthnumber> <tr> <td> <table> <tr> <td> <p> <a href="#"> <b>${blogItem.mainTitle} </a> </p> </td> </tr> <tr> <td> <p> ${blogItem.publishedDate?substring(0,10)} </p> </td> </tr> </table> </td> </tr> </#if> </#if> </#if> </#list> </table> </#if> </body> </html>
Here we are fetching the blog items for a particular month with the parameter as month in the web script URL. But if you don't specify this parameter, then the current month will be considered to fetch the blog items.
Once done with the development of a web script with all of the mentioned files, we need to store it to the Web Scripts Extensions folder in Alfresco Explorer. Navigate to the Company Home | Data Dictionary | Web Scripts Extensions folder. Create the folder structure as org/cignex/blogs
. Upload all of the three mentioned files here in this folder, as shown in the following screenshot:
Once done with this, we need to register our web script. Navigate to http://localhost:8080/alfresco/service/index
and click on the Refresh Web Scripts button. Now that our web script is registered, we can start using it with the URL.
Now in Drupal, we need to create a new page where we will display this month's blog entries. For that we will create a new module:
In the previous example, we saw how we can display the news headlines on the news portlet. Now, in this case study, we will learn to view the details about a particular news item. Suppose you have any J2EE-based application and you want to display the news page with some specific news item. This can be integrated with the earlier portlet example as well, like say, on the portal home page, you have one news portlet, which displays the news headlines, but when you click on any news item, you should be able to see that particular news item. However, here we will take the example of any J2EE web application and we will call this web script from a normal JSP page.
In this case study, as mentioned before, we will talk about the web script that will fetch the details of a particular news item. In this example, we will develop a Java-backed web script so that you can have an idea about how to create Java-backed web scripts. The response format will be HTML.
The description document, getNewsItem.get.desc.xml
, which describes the URL and the authentication mechanism for the web script is as follows:
<webscript> <shortname>Listing Of News Item</shortname> <description>Listing Of News Item for Cignex News page thru Webscript</description> <url>/org/cignex/news/getNewsItem.html?storeId={storeId}& newsId={newsId}</url> <authentication>user</authentication> </webscript>
In this example, instead of using JavaScript as the execution script controller, we will use Java Bean as a controller and perform our business logic to fetch the particular content and process that is in this Java class.
We will create a Java Bean class named GetNewsItem
, which extends the DeclarativeWebScript
class and will override the execute method as follows:
public class GetNewsItem extends DeclarativeWebScript { protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) { // Perform the business logic here in this method } }
Now, we need to configure this Bean in a Spring configuration file as a controller for a web script. For that we will create a configuration XML file named web-script-custom-context.xml
in tomcat/webapps/alfresco/WEB-INF/classes/alfresco/extension
.
Make an entry for this Java class as a Spring Bean in web-script-custom-context.xml
as follows:
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'> <beans> <!-- Web Script Storage --> <bean id="webscript.org.cignex.news.getNewsItem.get" class="com.cignex.web.scripts.bean.news.GetNewsItem" parent="webscript"> <property name="contentService" ref="ContentService" /> <property name="avmService" ref="AVMService" /> </bean> </beans>
The rendering template for the HTML response, getNewsItem.get.html.ftl
file, is as follows:
<#ftl ns_prefixes={"D", "http://www.alfrescobook.com/news"}> <#if m_news?exists> <table width="100%" cellspacing="0" cellpadding="0" border="0"> <tr> <#assign newsItem = m_news> <td> <h2>${newsItem.contentHeader}</h2> <#if newsItem.newsDate != ""> <strong>News Date:</strong> ${newsItem.newsDate} </#if> <#if newsItem.contentSubHeader != "" > <h4>${newsItem.contentSubHeader}</h4> </#if> <table width="50%" cellspacing="0" cellpadding="5" border="0"> <tr> <td> <tr> <h4> ${newsItem.imageTitle}</h4> <#if newsItem.contentGraphic != "" > <td> <img src="${newsItem.contentGraphic}" border=0/> </td> </#if> </tr> </td> <td> <strong> ${newsItem.imageCaption}</strong> </td> </tr>0 <tr> <td> ${newsItem.contentText} </td> </tr> </table> </td> </tr> </table> </#if> </html>
Here we are fetching the details of a news item for a particular news ID, based on the ID passed; the details for that news item will be returned from Alfresco.
In this example, we have not used the Lucene Search API; rather we have used AVM APIs and this web script is flexible enough to search in any of the sandboxes for any web project. Suppose you want to search for some content in your own User Sandbox (the content is still not promoted to the Staging Sandbox); you can pass the store ID as wwwcignex—admin
. Here 'wwwcignex' is the web project name and 'admin' is the username, so wwwcignex—admin
will be the sandbox of the 'wwwcignex' web project for a user 'admin'.
This will help in testing the content, which you have created, before submitting this change to the Staging Sandbox.
Once done with development of the web script with all of the three mentioned files, we need to store it to the Web Scripts Extensions folder in Alfresco Explorer. Navigate to Company Home | Data Dictionary | Web Scripts Extensions and create the folder structure as org/cignex/news
. Upload all of the three mentioned files here in this folder, as shown in the next screenshot:
Once we have done this, we need to register the web scripts.
Go to http://localhost:8080/alfresco/service/index
and click on the Refresh Web Scripts button. Now that our new web script is registered, we can start using it with the URL.