Alfresco coding best practice : how to safely call java services ?

January 6, 2010

In alfresco there are two ways of calling a repository service: e.g., lower case “nodeService” and upper case “NodeService” etc (similarly for rest of the available repository services).

To be able to use a service bean in your custom code, you usually use a spring configuration file to inject it dynamically in your class (using spring IOC).
So in your spring configuration file, for your class “com.mycompany.MyBeanClass”, you can choose to inject the Alfresco service (nodeService below) using the “nodeService” (lower case) or “NodeService”(upper case) naming convention:

   <bean id="myBean" >
      <property name="nodeService">
          <ref bean="nodeService" />
      </property>
   </bean>

or:

   <bean id="myBean" >
      <property name="nodeService">
          <ref bean="NodeService" />
      </property>
   </bean>

As a coding best practice it is highly recommended to use services with upper case “NodeService” etc., because this “nodeService” bypasses security check, transaction check, etc.
The technical explanation is that Alfresco use AOP (Aspect-Oriented Programming) to expose services either as standard spring bean, or as “AOP proxies”.
To better understand that, let’s have a look at these 2 files, which contains a reference to the ContentService bean:

/webapps/alfresco/WEB-INF/classes/alfresco
public-services-context.xml
content-services-context.xml

The public-services-context.xml contains a reference to the “ContentService” (lower case) which is actually a proxy object (AOP proxy) for the  “contentService” (lower case) referenced in content-services-context.xml:

public-services-context.xml

    <bean id="ContentService">
        <property name="proxyInterfaces">
            <value>org.alfresco.service.cmr.repository.ContentService</value>
        </property>
        <property name="target">
            <ref bean="contentService"/>
        </property>
        <property name="interceptorNames">
            <list>
                <idref local="ContentService_transaction"/>
                <idref local="AuditMethodInterceptor"/>
                <idref local="exceptionTranslator"/>
                <idref bean="mlContentInterceptor"/>
                <idref bean="ContentService_security"/>
            </list>
        </property>
    </bean>
 

content-services-context.xml

   <!-- Abstract bean definition defining base definition for content service -->
   <bean id="baseContentService" abstract="true" init-method="init">
      <property name="retryingTransactionHelper">
          <ref bean="retryingTransactionHelper"/>
      </property>
      <property name="dictionaryService">
          <ref bean="dictionaryService" />
      </property>
      <property name="nodeService">
          <ref bean="nodeService" />
      </property>
      <property name="transformerRegistry">
          <ref bean="contentTransformerRegistry" />
      </property>
      <property name="policyComponent">
          <ref bean="policyComponent" />
      </property>
      <property name="avmService">
          <ref bean="avmService"/>
      </property>
      <property name="imageMagickContentTransformer">
         <ref bean="transformer.ImageMagick" />
      </property>
      <property name="eagerContentStoreCleaner" >
         <ref bean="eagerContentStoreCleaner" />
      </property>
   </bean>
  
   <bean id="contentService" parent="baseContentService">
      <property name="store">
          <ref bean="fileContentStore" />
      </property>
   </bean>

In the public-services-context.xml, we can see a list of interceptors, which force the execution of security check (ContentService_security) or audit action (AuditMethodInterceptor) or even transaction context (ContentService_transaction).

        <property name="interceptorNames">
            <list>
                <idref local="ContentService_transaction"/>
                <idref local="AuditMethodInterceptor"/>
                <idref local="exceptionTranslator"/>
                <idref bean="mlContentInterceptor"/>
                <idref bean="ContentService_security"/>
            </list>
        </property>

So when someone call directly the the  “contentService” (lower case), all these check are bypassed. This can leads to security issue (for instance) because the Alfresco system in this case does not evaluate the security before running the corresponding service operation.
So the conclusion is in almost all the cases it is best to use upper case services, especially in places where we know that there is a possibility of “no proper security check”. The only case where minor case service might be use safely is likely to be “admin treatment” (like batch), when one knows that we do not need to check security for such technical operation. But keep in mind that transaction are also bypassed, so I think they should be explicitly managed at the service call level if needed.