Skip navigation
All Places > Alfresco Content Services (ECM) > Blog > 2011 > July
2011

Sub-Component Evaluations

Posted by ddraper Jul 29, 2011

Introduction

In the last blog post I showed how to extend a Component and hide its default Sub-Component through the use of an Evaluation. In this blog post I'm going delve further into Evaluations and introduce Evaluators demonstrating how they should be defined and how they can be used. These extensibility features are available in the latest Alfresco Community source code and will later appear in Alfresco Enterprise 4.0.

 

Tutorial

We're going to create a similar module to the last one - but instead of hiding the title bar on the user dashboard we're going to hide the title bar on the site dashboard, but only if the site has a specific name.

 

Update the 'blog-demo.xml' file and add the following module definition:

 

<module>
    <id>Blog Module (Conditionally Hide Title)</id>
    <components>
        <component>
            <scope>page</scope>
            <region-id>title</region-id>
            <source-id>site/{site}/dashboard</source-id>
            <sub-components>
                <sub-component id='default'>
                    <evaluations>
                        <evaluation id='HideIfBlogDemoSite'>
                            <evaluators>
                                <evaluator type='blog.demo.evaluator'></evaluator>
                            </evaluators>
                            <render>false</render>
                        </evaluation>
                    </evaluations>
                </sub-component>
            </sub-components>
        </component>
    </components>
</module>

 

Site dashboards are similar to user dashboards in that new configuration is created from a preset for each new site. This means we need to target our component using the {site} parameter (we could of course accomplish the same objective by specifying a specific site in the 'source-id' if we wanted, but this blog is about evaluators!)

 

The evaluator 'type' attribute must map to a Spring bean id defined in the application context. We therefore need to create this Evaluator and defined it as a Spring bean.

 

First create the following class:

 

package blog.demo;

import java.util.Map;
import org.springframework.extensions.surf.RequestContext;
import org.springframework.extensions.surf.extensibility.impl.DefaultSubComponentEvaluator;

public class BlogDemoEvaluator extends DefaultSubComponentEvaluator
{
    public boolean evaluate(RequestContext context, Map<String, String> params)
    {
        boolean result;
        String site = context.getUriTokens().get('site');
        if (site == null)
        {
            site = context.getParameter('site');
        }
        result = (site != null && site.equals('blogdemo'));
        return result;
    }
}

 

Then create a new file called 'spring-surf-extensibility-context.xml' and place it in a new 'org.springframework.extensions.surf' package in your JAR file (any file that fits the pattern 'org.springframework.extensions.surf.*-context' will get processed into the application context). This file should contain the following:

 

<?xml version='1.0' encoding='UTF-8'?>
<beans xmlns='http://www.springframework.org/schema/beans'
              xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
              xsi:schemaLocation='http://www.springframework.org/schema/beans
                                  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd'>

    <bean id='blog.demo.evaluator' class='blog.demo.BlogDemoEvaluator'/>
</beans>

 

Build and deploy your JAR to Alfresco Share as described in the previous blog posts and then restart the web server.

 

Log on to Alfresco Share and create 2 new sites: 'BlogDemo' and 'SomeOtherSite' - as the new module has not yet been deployed you should see the title bar on both sites.

 

Screen shot of Blog Demo site with the title displayedScreen shot of Some Other Site With Title displayed

 

Now go to the Module Deployment WebScript (http://localhost:8080/share/page/modules/deploy - assuming you're using the defaults, adjust as necessary) and deploy the new module (see previous posts for detailed instructions on deploying modules).

 

When you refresh the dashboard pages for the 'BlogDemo' and 'SomeOtherSite' sites you should see that the title bar is displayed on the latter, but not the former.

 

Screen shot of Blog Demo Site with no title

 

Evaluators can also accept parameters in order that they can be easily re-used. Update the 'blog-demo.xml' file so that the evaluator is configured as follows:

 

<evaluator type='blog.demo.evaluator'>
<params>
        <site>someothersite</site>
    </params>
</evaluator>

 

...and modify the BlogDemoEvaluator class 'evaluate' method so that it looks like this:

 

public boolean evaluate(RequestContext context, Map<String, String> params)
{
    boolean result;
    String site = context.getUriTokens().get('site');
    if (site == null)
    {
        site = context.getParameter('site');
    }

String targetSite = params.get('site');
    result = (site != null && site.equals(targetSite));
    return result;
}

 

Re-build and re-deploy the JAR and then restart the web server and you should now see that the 'SomeOtherSite' title bar is hidden and the 'BlogDemo' title bar is displayed.

 

Screenshot of Some Other Site With No Title

 

When setting evaluator parameters the element name is the parameter key and the element value is the parameter value. All of the configured parameters will be passed as the 'params' argument when the 'evaluate' method is called. Parameters can also accept token substitution - so you could set a parameter of:

 

<site>{site}</site>

 

Which would make the evaluator pass regardless of whatever site dashboard is being displayed (although this would be a rather pointless exercise!).

 

Background Information

 

Evaluations

The purpose of an Evaluation is to dynamically alter a Sub-Component based on the current request. This is done by either changing the Web Script URL, updating the properties passed to the Web Script or preventing the Sub-Component from rendering entirely (which was demonstrated in the previous blog post).

 

A Sub-Component should be defined with a default Web Script URL and properties which will be used if no evaluations are configured or none of the evaluations that are configured evaluate successfully. If more than one evaluation is defined then each will be processed in turn and the first to evaluate successfully will have the opportunity to override the Web Script URL and/or properties or to hide the Sub-Component.

 

Evaluations are processed in the order in which they are defined in the configuration file. Evaluations defined in extension modules are processed before evaluations in the 'base' Component configuration. If more than one extension module defines evaluations for the same Sub-Component then they processed in the deployment order defined through the Module Deployment UI (/service/page/modules/deploy).

 

We've used evaluations internally to update add, hide and change various Sub-Components in the Document Library page depending upon what type of site is being viewed.

 

Evaluators

Every Sub-Component Evaluator must be configured in the Spring application context as a bean and must implement the org.springframework.extensions.surf.extensibility.SubComponentEvaluator interface. The interface defines a single method called evaluate that takes a org.springframework.extensions.surf.RequestContext and a parameter map as arguments.

 

A Sub-Component Evaluation will call the evaluate method on each Evaluator that is configured with and will only be considered to have evaluated successfully if every evaluate method returns true.

 

A number of SubComponentEvaluator instances are already configured in the Alfresco Share application context for testing various criteria (e.g. whether or not the requested page relates to a particular site) but it is a fairly simple exercise to create your own instances.

 

The RequestContext instance passed into the evaluate method will let you access pretty much everything you need to know about the request being evaluated (there's too much information to list, the best way to see everything available would be to attach a Java debugger to the web server and set a break point in an evaluator an inspect an instance).

 

 

 

 

 

<module>

 

<id>Blog Module (Conditionally Hide Title)</id>

 

<components>

 

<component>

 

<scope>page</scope>

 

<region-id>title</region-id>

 

<source-id>site/{site}/dashboard</source-id>

 

<sub-components>

 

<sub-component id='default'>

 

<evaluations>

 

<evaluation id='HideIfBlogDemoSite'>

 

<evaluators>

 

<evaluator type='blog.demo.evaluator'></evaluator>

 

</evaluators>

 

<render>false</render>

 

</evaluation>

 

</evaluations>

 

</sub-component>

 

</sub-components>

 

</component>

 

</components>

 

</module>

 

 

This post assumes a reasonable sys-admin level of knowledge of Alfresco and assumes you are already familiar with setting up the Alfresco Repository in a cluster configuration and also familiar configuring an Apache web-server instance.

 

For high availability and performance reasons, clustering the Alfresco Repository is a commonly used setup. But it is also easy to use Apache for both load balancing an Alfresco Share web-tier against an Alfresco cluster and also to cluster (i.e. web farm) the Alfresco Share web-tier itself – or both those combined together. This post examines the configuration required for those setups using Alfresco 3.4/4.0.

 

These are the three setups we will be considering. Note that all examples assume you have already successfully setup a working Alfresco 3.4/4.0 repository cluster. It also assumes you are deploying the Share web-tier(s) to separate TomCat instance, not the same one as the Alfresco repository instances.

 

  1. Single Share instance load balanced to a repository cluster e.g. Browser->Share->Apache->Repo Cluster
    1. Share tier cluster to a single repository instance e.g. Browser->Apache->Share Cluster->Repo
    2. Share tier cluster load balanced to a repository cluster e.g. Browser->Apache->Share Cluster->Apache->Repo Cluster

     

    NOTE: all the example config below mentions “localhost” - as for testing purposes I set this all up on a single machine, changing the various TomCat ports as I go – but in reality you would probably be using difference machine instances (virtual or otherwise) for each, so care must be taken when setting up the config!

     

    For setup 1. Configuring Share to point to an Apache reverse proxy that is setup to load balance to a multi-node Alfresco repository cluster.

     

    You should be familiar with “share-config-custom.xml” – generally located in \tomcat \shared\classes\alfresco\web-extension and used to override the common Share startup parameters, including the remote endpoint locations. There is an example “share-config-custom.xml.sample” provided in the Alfresco distribution as a starting point. So add this section:

       <config evaluator='string-compare' condition='Remote'>

          <remote>

             <endpoint>

                <id>alfresco-noauth</id>

                <name>Alfresco - unauthenticated access</name>

                <description>Access to Alfresco Repository WebScripts that do not require authentication</description>

                <connector-id>alfresco</connector-id>

                <endpoint-url>http://localhost:8089/alfresco/s</endpoint-url>

                <identity>none</identity>

             </endpoint>


             <endpoint>

                <id>alfresco</id>

                <name>Alfresco - user access</name>

                <description>Access to Alfresco Repository WebScripts that require user authentication</description>

                <connector-id>alfresco</connector-id>

                <endpoint-url>http://localhost:8089/alfresco/s</endpoint-url>

                <identity>user</identity>

             </endpoint>


             <endpoint>

                <id>alfresco-feed</id>

                <name>Alfresco Feed</name>

                <description>Alfresco Feed - supports basic HTTP authentication via the EndPointProxyServlet</description>

                <connector-id>http</connector-id>

                <endpoint-url>http://localhost:8089/alfresco/s</endpoint-url>

                <basic-auth>true</basic-auth>

                <identity>user</identity>

             </endpoint>

          </remote>

       </config>

    The endpoint-url elements are the important bits - set them to your Apache location, in my example this is “localhost:8089”.

     

    And in your Apache httpd.conf file, enable the various proxy/balancer modules (these modules are used in both examples - so you might not actually need them all, but there is no harm in enabling them):

     

    LoadModule proxy_module modules/mod_proxy.so

    LoadModule proxy_ajp_module modules/mod_proxy_ajp.so

    LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

    LoadModule proxy_connect_module modules/mod_proxy_connect.so

    LoadModule proxy_http_module modules/mod_proxy_http.so

     

    And then add this section:

     

    # Reverse Proxy Settings (cluster load balancing)

    ProxyRequests Off

    #NOTE: sticksession only required if non-default Alfresco auth stack is used i.e. NTLM2 or similar

    #stickysession=JSESSIONID|jsessionid nofailover=On

    ProxyPass /alfresco balancer://app

    ProxyPassReverse /alfresco balancer://app

    <Proxy balancer://app>

      #Add your Alfresco cluster nodes here

      BalancerMember ajp://localhost:8009/alfresco route=tomcat1

      BalancerMember ajp://localhost:8014/alfresco route=tomcat2

    </Proxy>

     

    The various cluster nodes should be added into the Proxy element as above, then in each Alfresco node instance TomCat server.xml, ensure the AJP connector is enabled and that the port matches the BalancerMember setting above, also ensure the Engine element jvmRoute attribute is set to match i.e using the above example:

    <Connector port='8009' protocol='AJP/1.3' redirectPort='8443' />

    and

    <Engine name='Catalina' defaultHost='localhost' jvmRoute='tomcat1'>

    Note that sticky sessions are not required by default when using the standard Alfresco authentication stack as the communication between Share and Alfresco is completely stateless and does not require a web Session. This means that your Apache instance can load balance the requests, even multiple Ajax requests from a single page instance, across multiple Alfresco cluster nodes to give the best performance. However, the side effect of this is that Lucene results will potentially differ in a cluster and Lucene is used to retrieve even simple things like Share document list and various picker results in 3.4 and below. The good news is that from Alfresco 4.0 and onwards, Lucene is no longer used for list or picker results by default (canned DB queries are used instead), so sticky sessions are not required in 4.0.

     

    For setup 2. We need to configure an Apache forward proxy to point to multiple Share web-tier instances, also each user browser must be configured to point to the Apache proxy. Load balancing can of course be used, although the simple Apache config below doesn’t show that. This time however sticky sessions are required between the browser and the Share instance as a small amount of Session state is managed for each user in Share.

     

    Apache httpd.conf (not a load balanced example but you get the idea)

    # Forward Proxy Settings

    ProxyRequests On

    ProxyVia On

    <Proxy *>

      Order Allow,Deny

      Allow from all

    </Proxy>

     

    You may be familiar with “custom-slingshot-application-context.xml” – generally located in \tomcat \shared\classes\alfresco\web-extension and used to override the Spring application context beans for Share. There is an example “custom-slingshot-application-context.xml.sample” provided in the Alfresco distribution as a starting point.

     

    So add this section  to each Share tomcat instance to disable the appropriate web-tier caches (this example actually comes from the currently shipped custom-slingshot-application-context.xml.sample, which is where the helpful comments come from):

     

       <!-- Web-tier cluster configuration -->

       <!-- Enable this section if you are clustering or load balancing the share.war i.e. multiple web-tiers behind a proxy -->

       <!-- If you have a single web-tier running against an Alfresco cluster via a reverse proxy you don't need this -->

       <bean id='webframework.slingshot.persister.remote' class='org.springframework.extensions.surf.persister.PathStoreObjectPersister' parent='webframework.sitedata.persister.abstract'>

          <property name='store' ref='webframework.webapp.store.remote' />

          <property name='pathPrefix'><value>alfresco/site-data/${objectTypeIds}</value></property>

          <property name='noncachableObjectTypes'>

             <set>

                <value>page</value>

                <value>component</value>

             </set>

          </property>

       </bean>

     

    For setup 3. Use a combination of the above two setups! So modify the “custom-slingshot-application-context.xml“ and “share-config-custom.xml” for each Share TomCat instance to configure the forward and reverse proxy Apache instances (you will need two Apache instances for this) and to disable the web-tier caches.

    Introduction

    In my last blog I introduced some of the new extensibility features that are now available in the latest Alfresco Community source code and will later appear in Alfresco Enterprise 4.0. I demonstrated how to create and deploy an extension module that added some extra content to a user dashboard page in Alfresco Share. In this blog I'm going to demonstrate how to use an extension module to hide some extra content in an Alfresco Share page.

     

    Tutorial

    Our previous module added content to the title bar on the user dashboard, let's take the opposite tack and write a module to completely hide it.  If we were targeting a different Component we'd use SurfBug to identify the title bar region-id, source-id and scope properties (see the previous post for a refresher on how to do this) but as we're modifying the same Component we can just copy the configuration from the 'blog-demo.xml' file that you previously created.

     

    Add another <module> entry into the <modules> element - as follows:

    <module>
        <id>Blog Module (Hide Title)</id>
            <components>
                <component>
                     <region-id>title</region-id>
                     <source-id>user/{userid}/dashboard</source-id>
                     <scope>page</scope>
                     <sub-components>
                         <sub-component id='default'>
                             <evaluations>
                                 <evaluation id='guaranteedToHide'>
                                     <render>false</render>
                                 </evaluation>
                             </evaluations>
                         </sub-component>
                     </sub-components>
                 </component>
         </components>
     </module>


    Then follow these steps (they should be familiar from the previous tutorial):

      1. Re-build your JAR file,
      2. Copy it into the 'webapps/share/WEB-INF/lib directory'
      3. Restart the server
      4. Open http://localhost:8081/share/page/modules/deploy in a web browser
      5. If you still have 'Blog Module (New Content)' deployed, undeploy it by selecting it and clicking the 'Remove' button
      6. Deploy 'Blog Module (Hide Title)' by selecting it and clicking the 'Add' button
      7. Click 'Apply Changes' to save your module deployments
      8. Logon to Alfresco Share and you should see that the title bar is no longer displayed.


    Screen shot showing hidden title bar

     

    It probably seems like that's a lot of XML to achieve a fairly simple task, but we're really only just scratching the surface of what is possible. Let's explore some of the elements of this configuration more closely...

     

    Parametrized source-id mapping

    Every Alfresco Share user gets their own dashboard page (which enables them to customize the layout to suit their own needs) but each user dashboard is generated from a single preset.  In the previous blog we targeted only the Admin user dashboard by extending the title region on the 'user/admin/dashboard' template, but here we're targeting all user dashboards by specifying the source template 'user/{userid}/dashboard'.

     

    Extending Existing Sub-Components

    When the dashboard pages were first created the concept of Sub-Components in Spring Surf did not exist and consequently if you search through the existing dashboard configuration files you won't find any mention of Sub-Components.  Spring Surf automatically converts these 'legacy' Components into the new extensible Components containing a single Sub-Component with the ID 'default'.

     

    This allows us to add new content to these legacy Components (as we did in the last blog) or customize the original content without effecting any new content. In this instance by specifying a Sub-Component with an ID of 'default' we are not adding new content but changing the behaviour of the original content. Multiple modules can extend the same Component which is why the deployment order of modules can be important.

     

    I'll be exploring Sub-Components in greater detail in a later blog.

     

    Sub-Component Evaluations

    Every Sub-Component can optionally have zero or more evaluations. Each evaluation acts like an AND-gate to a series of evaluators where an evaluation is considered successful if no evaluators fail. If an evaluation contains no evaluators then it is still considered to have evaluated successfully because nothing has failed.

     

    The purpose of an evaluation is to change the behaviour of a Sub-Component in one of three ways:

     

    1. Change the Web Script that renders the content by specifying a new URL
    2. Change the default properties (and/or provide new properties) that are passed to the Web Script
    3. Control whether or not the Sub-Component is actually rendered.


    In this example we're simply overriding the default behaviour of the Sub-Component to prevent it from rendering by setting the <render> element to have a value of false (this defaults to true) if not defined.

     

    I'll be exploring evaluations and evaluators in greater detail in a later blogs, but the purpose of this tutorial is to provide an introduction into customizing existing content.

     

    Some Additional Notes

    It would have been possible to add the <sub-component> elements (and its children) into the module created in the previous blog as single module can update multiple Components and Sub-Component.  Adding the 'hide' configuration as a separate module allows us to deploy and undeploy both independently. If you deploy both modules you'll see that it's the new content is still rendered despite the the title bar being hidden. It is not necessary to restart the web server between module deployment changes - providing you remember to click the 'Apply Changes' button the updates will be shown the next time you refresh the Alfresco Share page.

     

     

     



    Introduction

    This is the first in a series of blogs that is going to describe some of the new extensibility features that are now available in the latest Alfresco Community source code and will later appear in Alfresco Enterprise 4.0.

     

    A complaint that we sometimes hear about Alfresco Share is that it is not particularly easy to customize. So for Alfresco Enterprise 4.0 we're going to provide a number of different ways in which to make customization easier. One of the ways that it will be possible to do this is by taking advantage of new extensibility features that have been added into the Spring Surf framework upon which Alfresco Share is built.

     

     

     

    The primary goal of these features was to ensure that it wasn't necessary to completely re-write Alfresco Share. Although we wanted to introduce new concepts, we didn't want to force developers to completely re-learn how Alfresco Share is put together.

     

    In later blogs I'm going to explore the new framework in detail and describe all the features and exactly what's changed, but as an introduction I'd like to demonstrate how to add some new content to an existing Alfresco Share page.

     

    Tutorial

    The quickest way to add content to an Alfresco Share page is to create the content as a Web Script and then add a new Sub-Component an existing Component on the page.

     

    The content is going to be provided by an Extension Module deployed into Alfresco Share as a JAR file. The JAR file needs to contain the following packages:

     

    • alfresco.site-data.extensions
    • alfresco.site-webscripts


    First of all, let's create some content as a Web Script, the actual content isn't important so we'll  keep it simple. A Web Script needs a minimum of 2 files; a descriptor and a template (this isn't a blog on Web Scripts so I'm going to assume you know about them, but if you don't - there's lots of information available here.

     

    Create a new file called 'new-content.get.desc.xml' containing the following:

    <webscript>
        <shortname>New Content</shortname>
        <url>/blog/demo/new-content</url>
        <family>Blog Demo</family>
    </webscript>

     

    Create a new file called 'new-content.get.html.ftl' containing the following:

    <div>
        Hello World!
    </div>

    Build your JAR file so that files are in the 'alfresco.site-webscripts' package. Copy the JAR file into the 'webapps/share/WEB-INF/lib' folder in Tomcat (or the equivalent location in whatever web server you're using) and start (or restart) the server.  It should be noted that placing a JAR in this folder means that the it won't survive an upgrade or WAR re-deploy - but placing it there is sufficient for the purposes of this tutorial.

     

    Open a browser at the URL http://localhost:8080/share/service/index (assuming you're running the server on your local machine and you haven't tinkered with the port and application context settings) and you will be taken to the Web Scripts Home page. Check that you can see a link for 'Browse 'Blog Demo' Web Scripts' (this indicates that your new Web Script has been successfully registered).

     

    Screenshot showing "Blog Demo" Web Script family highlighted

     

    We now want to select a location to add our new content - to help with this we're going to use a new tool called 'SurfBug' (which I'll cover in greater detail in a later blog). Log onto Alfresco Share (http://localhost:8080/share) in a separate browser window or tab, then switch back to the 'Web Scripts Home' page and scroll to the bottom and click the button labelled 'Enable SurfBug' (the page should refresh and the button should have changed to say 'Disable SurfBug'.

     

    A screenshot of te Web Scripts Home page showing the enable surf bug buttonScreenshot showing the Surf Bug status page

     

    Switch back to the Alfresco Share window and refresh the page. You should now see that the user dashboard now has some red boxes shown on it indicating the Sub-Components that are present on the page. Click in any of the boxes and a pop-up will be displayed providing information about that Sub-Component and its parent Component.

     

    Screen shot of Share displaying Surf Bug information

     

    Click on the title bar and make a note of the 'Component Details', in particular the 'region-id', 'source-id' and 'scope' values which (if you've logged in as 'Admin') will be:

     

    • title
    • user/admin/dashboard
    • page


    This is the information that you'll need to add a new Sub-Component to that existing Component. Create a new file called 'blog-demo.xml' containing the following:

    <extension>
        <modules>
            <module>
                <id>Blog Module (New Content)</id>
                <components>
                    <component>
                        <region-id>title</region-id>
                        <source-id>user/admin/dashboard</source-id>
                        <scope>page</scope>
                        <sub-components>
                            <sub-component id='New_Content' index='25'>
                                <url>/blog/demo/new-content</url>
                            </sub-component>
                        </sub-components>
                    </component>
                </components>
            </module>
        </modules>
    </extension>

    Note how the target Component is specified using the data taken from SurfBug and how the Sub-Component specifies the URL of the new Web Script created.

     

    Re-build the JAR so that file is placed in the 'alfresco.site-data.extensions' package, copy the new JAR over the old one in the 'webapps/share/WEB-INF/lib' folder and restart the web server.

     

    In order for the new content to be displayed the module needs to be deployed. Module deployment is a new feature in Alfresco 4.0 that is done through a Web Script found at: http://localhost:8081/share/service/modules/deploy. Navigate to this page and you should see a list of 'Available Modules' and a list of 'Deployed Modules'. Initially you should see the following 2 modules available:

     

    • Alfresco Portlet Extension
    • Blog Module (New Content)


    Select 'Blog Module (New Content)' and click the 'Add' button to move it into the 'Deployed Modules' list, then click the 'Apply Changes' button (you should notice that the 'Last update' time stamp changes). This action only needs to be done once as Module Deployment data is saved into the Alfresco Repository.

     

    Module Deployment page with the blog module undeployed

     

    Module deployment page with the blog module deployed

     

    Now log back into Alfresco Share and you should see that the content from the new Web Script is displayed above the title bar:

     

    Screenshot of Share user dashboard with new content

    wabson

    Custom Web Previews in Share

    Posted by wabson Employee Jul 21, 2011
    Note: This post discusses how document previews may be customized in Alfresco Share 3.x. In version 4.0 onwards, an improved method is available, based on a plugin framework. See my presentation Customizing Web Previews at Alfresco's DevCon 2012 event for more details.



    I was asked by a partner today how one would go about enhancing the document details page in Share to better support previewing of specific file types.



    Share's built-in Flash previewer provides great browser-based previews across a whole range of different document types, from PowerPoint files to PDFs. But often you may only be dealing with a couple of different content types, and you may need a wider set of features in your viewer, specific to those content types.



    Or, you may want to add support for an additional content type, not supported by the built-in web previewer.



    Either way, it is not difficult to add support for other types of previewers. These could be based on Flash widgets, similar to the web previewer, or other technologies such as Java applets or ActiveX controls. Increasingly the HTML5 support in modern browsers, coupled with modern processors, can perform a lot of heavy lifting that previously required a plug-in.



    A good example is provided by Share Extras, in the form of the Media Previews add-on. This uses a third-party Flash component to preview video and audio content in the browser, wrapped by a client-side JS module, but the basic approach is the same regardless of the technology you're choosing. Basically, if you can embed a previewer or player on a website, you can integrate it into Share.







    The first step is to read the documentation for the previewer you're using. Work out which files are required to make it work and how they are referenced in the HTML mark-up on the page.



    The files may consist of static resources such as Flash files, JavaScript scripts, CSS files and even compiled code packages (for Java/ActiveX). Sometimes they may be hosted on third-party servers, but normally you will need to bundle them yourself.



    Assuming the latter case, you should add them into a new directory inside the Share webapp, and ideally in a collection of sub-directories within that. For example, the Media Previews files are placed in the directory /extras/components/preview, mirroring the structure used by Share's web preview, but in a separate subdirectory reserved for Share Extras add-ons.



    The next step is to modify the web script that hooks in the web previewer. You can find the files for this web-preview.get web script in the following directory in the Share webapp



    WEB-INF/classes/alfresco/site-webscripts/org/alfresco/components/preview



    Take a look in web-preview.get.html.ftl. You should see that it inserts the standard web previewer using a JavaScript module, instantiated inside a <script> element.



    Now look inside the customised web-preview.get.html.ftl in the Media Previews source code. You will see that it uses a Freemarker <#if> directive to choose between the standard previewer and the custom ones, based on the content item's MIME type.



    Although the two custom previewers used here also use client-side code to instantiate themselves on the page, you could equally just use an <object> tag to reference the Flash .swf files directly. The benefit of wrapping the previewer with JavaScript code is that it allows you to apply more complex logic, such as detecting if the user has the correct version of Flash installed, or hooking the previewer into page events to update the preview when a new version of the content is uploaded.



    Once you're happy with the mark-up you want to add into the Freemarker file to insert your custom previewer, you can insert this into the file. But rather than overwriting the original, you should use Spring Surf's override mechanism to separate your custom code from the original version.



    To override the HTML template, take a copy of the web-preview.get.html.ftl and place it into the following directory, after first creating any missing directories.



    <TOMCAT>/shared/classes/alfresco/web-extension/site-webscripts/org/alfresco/components/preview



    When you reference your static files that you added into the webapp earlier, you should use URLs such as ${url.context}/mydir/path/to/asset.swf, or in 3.4 ${url.context}/res/mydir/path/to/asset.swf. The url.context variable will automatically resolve to Share's webapp context path, i.e. share by default, and mydir/path/to should be the directory structure you created in the webapp.



    To reference the item's content by URL, you can use an expression such as ${url.context}/proxy/alfresco/api/node/${node.nodeRef?replace('://', '/')}/content in your Freemarker markup. To reference the content of a named thumbnail, add /thumbnails/imgpreview to the end of the URL, where imgpreview is the name of the thumbnail.



    If your previewer does use some JavaScript code or custom CSS styles from additional files which you've bundled, you will need to reference these files in web-preview.get.html.ftl. See the customised web-preview.get.html.ftl in Share Extras for an example, and note the override mechanism is exactly the same as for the .html.ftl template. You are recommended to use the <@script> and <@style> macros provided by component.head.inc, but note that with <@script> you will need to bundle a compressed version of your JavaScript file(s) with the -min.js suffix.



    When you've finished making changes in your override files you can put these into effect by refreshing Share's list of web scripts or by restarting your Tomcat server.



    Once you're happy with your customisation, you'll want to create a dedicated project structure to manage your source files. So Share Extras also provide a sample project, complete with directory structure and an Ant build script that can be used to package up your add-on in JAR format.

    Filter Blog

    By date: By tag: