Extensibility Module Deployment

cancel
Showing results for 
Search instead for 
Did you mean: 

Extensibility Module Deployment

Intermediate II
1 24 4,834

Introduction

Having covered the basics of the new extensibility features that are currently available in the latest Alfresco Community source and will be available in Alfresco Enterprise 4.0 this module will focus in greater detail on module structure and their deployment.

Background

If you've been working through the previous tutorials you might have noticed that when deploying your modules (via http://localhost:8080/share/page/modules/deploy - if you're using the defaults) some additional options are displayed to the right of the screen when clicking on a module. This is the module deployment configuration and it provides the opportunity to override the default configuration of an extension.

Screenshot of module deployment highlighting the evaluator options

Even if a Module is deployed the function it provides may not be applicable to every request. Therefore a Module can be configured to use an 'evaluator' that determines whether or not it should be used which is invoked on each request.

A deployed module will always be evaluated on every request.  A developer can optionally provide default Evaluator configuration but if it is omitted then Spring Surf will automatically apply the default application Evaluator (as defined in the Spring application context). By default Spring Surf defines a default application Evaluator that always results in the module being applied to each request. When you deploy any module you have the option of keeping the default Evaluator (which will either be the application default or will be have been explicitly defined in the configuration) or selecting your own.

Module Evaluators are just Spring beans like Sub-Component Evaluators and technically a single bean can be both a Module and Sub-Component Evaluator providing it implements both the 'org.springframework.extensions.surf.extensibility.ExtensionModuleEvaluator' and 'org.springframework.extensions.surf.extensibility.SubComponentEvaluator' interfaces.  However, a Module Evaluator takes precedence over a Sub-Component Evaluator in the sense that it will be evaluated first, and if the evaluation fails then the Sub-Components in the module will not even get the opportunity to be evaluated. Essentially though they are intended to perform the same function, i.e. compare data in the current request with against a set of configured parameters to see if the request meets the evaluation criteria.

The default Module Evaluator is configured in the Spring application context with the id 'default.extensibility.evaluator' that maps to the Class 'org.springframework.extensions.surf.extensibility.impl.ApproveAllModulesEvaluator' which (as its name suggests) will always evaluate to true. Another Evaluator available 'out of the box' has the bean id 'config.approval.evaluator'.  If you select this as the Evaluator when deploying a Module you will see that it asks for a single property with the key 'apply' which determines whether or not the Module gets applied (e.g. if you set the value as 'true' then the Module will always be applied, if you set it to anything else then the Module will never be applied).

Tutorial

Try this out with one of the previously created modules. It is not necessary to restart the server - simply browse to the module deployment WebScript UI, select the 'config.approval.evaluator' and set the 'apply' property to 'false' and when you refresh the previously affected Alfresco Share page you will see that the module is no longer be applied (NOTE: You must click the 'update' button to apply the change to the  module and then click the 'Apply Changes' button to persist your  changes).

Screen shot showing alternative evaluator selected

To achieve the same objective through configuration update the module configuration to contain the following (NOTE: only a fragment of the module config is shown - see the earlier blogs for the complete configuration):

<module>
    <id>Blog Module (New Content)</id>
    <evaluator type='config.approval.evaluator'>
        <params>
            <apply>false</apply>
        </params>
    </evaluator>

There are only a limited number of 'out-of-the-box' Evaluators available so it is likely that you may want to create your own. This process is very similar to creating a Sub-Component evaluator. First create the following Java class:

package blog.demo;

import java.util.Map;
import org.springframework.extensions.surf.RequestContext;

import org.springframework.extensions.surf.extensibility.ExtensionModuleEvaluator;

public class BlogModuleEvaluator implements ExtensionModuleEvaluator

{

    public static final String USER_PROP = 'user';

    public boolean applyModule(RequestContext context, Map<String, String> evaluationProperties)

    {

        String currUser = context.getUser().getId();

        String targetUser = evaluationProperties.get(USER_PROP);

        return (targetUser != null && targetUser.equals(currUser));

    }

    public String[] getRequiredProperties()

    {

        return new String[] { USER_PROP};

    }

}

Add the following line to your 'spring-surf-extensibility-context.xml' file:

<bean id='blog.module.evaluator' class='blog.demo.BlogModuleEvaluator'/>

Re-build and deploy your extension JAR and when you refresh the module deployment page after re-starting the web server you should be able to select your new module. Notice that the String array returned from the 'getRequiredProperties' method is used by the UI to provide a default set of properties to supply. These properties are currently not automatically validated in anyway so it's up to the Evaluator developer to check that all the data they require has been provided.

Screen shot showing deployment using custom evaluator

The custom Module Evaluator we've created will only apply the module for the user specified in the deployment configuration, so if you set the 'user' property to be 'admin' and then log onto Alfresco Share as 'admin' you will not see the title bar on the User Dashboard page (see example screenshots).

Screen shot showing the title bar hidden for user admin

Screen shot showing title bar shown for user "Dave"

24 Comments
Active Member
Hi David,

Is there a way to automatically deploy modules on bootstrap by default?
Intermediate II
Hi Florian,

Yes... you can add the following to your share-config-custom.xml file:

<config evaluator='string-compare' condition='WebFramework'>
      <web-framework>
     <module-deployment>
             <mode>auto</mode>
        </module-deployment>
   </web-framework>
</config>


Regards,
Dave
Active Member
Hi David,

Thanks for your excellent blogs about alfresco!

I had to change this  to this  to get it to work and then I can conditionally enable the title bar for specific users. But when I switch back to the defaults and click Apply Changes i get the following stacktrace:

2012-01-04 10:07:23,115  ERROR [extensibility.impl.BasicExtensibilityModuleHandler] [http-9090-4] The following exception occurred retrieving evaluator:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named '' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:527)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1083)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:274)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1079)
at org.springframework.extensions.surf.extensibility.impl.BasicExtensibilityModuleHandler.applyModule(BasicExtensibilityModuleHandler.java:275)
at org.springframework.extensions.surf.extensibility.impl.BasicExtensibilityModuleHandler.evaluateModules(BasicExtensibilityModuleHandler.java:242)
at org.springframework.extensions.surf.support.AbstractRequestContext.getEvaluatedModules(AbstractRequestContext.java:954)
at org.springframework.extensions.surf.support.AbstractRequestContext.getExtendingModuleFiles(AbstractRequestContext.java:975)
at org.springframework.extensions.webscripts.LocalWebScriptRuntimeContainer.getExtendingModuleFiles(LocalWebScriptRuntimeContainer.java:330)
at org.springframework.extensions.webscripts.AbstractWebScript.getExtensionBundle(AbstractWebScript.java:205)
at org.springframework.extensions.webscripts.AbstractWebScript.getResources(AbstractWebScript.java:336)
at org.springframework.extensions.webscripts.AbstractWebScript.createTemplateParameters(AbstractWebScript.java:662)
at org.springframework.extensions.webscripts.DeclarativeWebScript.execute(DeclarativeWebScript.java:91)
at org.springframework.extensions.webscripts.PresentationContainer.executeScript(PresentationContainer.java:70)
at org.springframework.extensions.webscripts.LocalWebScriptRuntimeContainer.executeScript(LocalWebScriptRuntimeContainer.java:239)
at org.springframework.extensions.webscripts.AbstractRuntime.executeScript(AbstractRuntime.java:372)
at org.springframework.extensions.webscripts.AbstractRuntime.executeScript(AbstractRuntime.java:209)
at org.springframework.extensions.webscripts.servlet.mvc.WebScriptView.renderMergedOutputModel(WebScriptView.java:99)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1047)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:817)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.alfresco.web.site.servlet.MTAuthenticationFilter.doFilter(MTAuthenticationFilter.java:74)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.alfresco.web.site.servlet.SSOAuthenticationFilter.doFilter(SSOAuthenticationFilter.java:307)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.valves.RequestFilterValve.process(RequestFilterValve.java:269)
at org.apache.catalina.valves.RemoteAddrValve.invoke(RemoteAddrValve.java:81)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:680)
Why is that?

Best regards
Intermediate II
Hi Peder,

Unfortunately it looks like Wordpress has helpfully removed some of your comment (I'm guessing some XML) so I can't see exactly what you've changed. It looks like the error is being caused by an attempt to look up an evaluator that doesn't exist.  If you want to move the discussion to the Surf development forum (https://forums.alfresco.com/en/viewforum.php?f=50) then it will be easier to include XML, code, screenshots, etc.

Regards,
Dave
Active Member
Hi David,

I'm having some trouble registering for the forum so I'll try to not use HTML tags.
I changed [lt]bean id='blog.module.evaluator'[/gt] to this [lt]bean id='blog.module.evaluator' class='blog.demo.BlogModuleEvaluator'[/gt] to get it to work and then when I reset the defaults in the /share/page/modules/deploy page I get the stacktrace
Intermediate II
Hi Peder,

Well, your change certainly looks correct (in fact it's what I have in my current JAR file) and I'm not seeing the problem occur.  I just want to check that you've rebuilt and re-deployed your JAR file and restarted the server so that the new changes to the Spring application context have taken effect?

That exception will occur if the Spring application context is incorrect and the bean isn't defined (or Spring cannot find the definition). I appreciate that this isn't perhaps the answer you're looking for but it does appear to be related to the Spring configuration and without actually being able to review your configuration it's hard to provide a better answer.

Regards,
Dave
Active Member
Hi David,

I solved my problem, I had a Typo in one of the xml files. Thanks for the quick response.

Best regards,

Peder
Active Member
[...] called “flash” and the other “noflash” (after the module has been applied obviously – see earlier posts for more information on [...]
Active Member
[...] The evaluator used is available “out-of-the-box” and for further information on evaluators read this post. The element contains a copy of the configuration taken from the [...]
Active Member
[...] module-deployment features (see blog by David Draper) [...]
Active Member
[...] The evaluator used is available “out-of-the-box” and for further information on evaluators read this post. The element contains a copy of the configuration taken from the [...]
Active Member
[...] called “flash” and the other “noflash” (after the module has been applied obviously – see earlier posts for more information on [...]
Active Member
Hi Dave,



Thanks a lot for your blog!



Regarding module evaluators I have a question. I created a PageModuleEvaluator which only applies customizations when my custom documentlibrary page is displayed. However the evaluator does not work when document library makes an AJAX call to fetch nodes. At that time the context.currentPage == null.



Is there a way to find what page I'm on when an AJAX call is executed?



Thanks in advance and best regards,

Bulat
Intermediate II
There isn't any page information because the XHR request (although launched from a page) is not requesting a page so there is no context. The only way I can see around this is to include the page id in the XHR request and make the evaluator check request parameters (or POST body) for the page information.
Active Member
I found also another workaround: to use 'referer' header from request:



String referer = context.getHeader(HttpHeaders.REFERER);

// match the value on a pattern to find the page name



I hope that header is always there to help me?..
Intermediate II
@Bulat That's not something I can guarantee I'm afraid !
Active Member
[…] would hide the “My Files” link if the user isn’t the Admin, or by deploying the Module with an evaluator (which pretty much allows you complete control over when the module is […]
Active Member
HI Dave,



How can I get  the node info here. My requirement is that I want to hide certain folder module based on the parent type for e.g. If the folder hierarchy is Country --> State --> City then I want to disable the city option in both Country and State space.



Thanks
Intermediate II
@Hiten - you'd need attempt to inspect the URL, resolve any node or path ... but you'll need to create a custom evaluator to do this.
Active Member
Hi Dave,

How can I control deployment order of modules, which overrides the same component? I found in documentation only one sentence:

'Note that multiple modules can extend the same component, which is why the deployment order of modules is important.'

But there are nothing about how to setup order. I can setup it in web interface, but I want have working system out of the box. Thanks.
Intermediate II
@Pavel you can control the order with the 'Up' and 'Down' buttons (see the screenshot). The last module 'wins' (as in, it's changes will be applied last).
Active Member
@Dave it's possible to control that without buttons? Some module parameters may be? I want install my system to several computers and it would be great if the system would works without hand work after install.
Intermediate II
@Pavel - yes, it is possible to configure each module with an 'auto-deploy-index' element to control order automatically - there's a discussion on this in this forum thread, see my comment here: https://forums.alfresco.com/comment/158108#comment-158108
Active Member
@Dave Thanks a lot! That's what I'm looking for