Sunday, September 20, 2015

How to safely inject alfresco service dependencies?


We can inject the repository service dependencies using 2 methods. One method is a lower case e.g. “contentService” bean ref and other method is upper case e.g. “ContentService” bean ref, similarly we can use "nodeService" or "NodeService".
To use a service in your custom implementation, you usually use a spring config (spring context) file to inject service bean dependencies. So in your spring context file, for your class for example “com.abhinav.CustomAction”, you can either use "nodeService" [lower-case] or "NodeService" [upper-case].

 Method 1-
   <bean id="customAction" class="com.abhinav.CustomAction">
      <property name="nodeService">
          <!-- Lower case -->
          <ref bean="nodeService"/>
      </property>
      <property name="contentService">
          <!-- Lower case -->
          <ref bean="contentService"/>
      </property>
   </bean>

Method 2-
<bean id="customAction" class="com.abhinav.CustomAction">
      <property name="nodeService">
          <!-- Lower case -->
          <ref bean="NodeService"/>
      </property>
      <property name="contentService">
          <!-- Lower case -->
          <ref bean="ContentService"/>
      </property>
</bean>

The best practice is that we should always use services with upper case “NodeService”, “ContentService”, “FileFolderService” etc. because this lower case “nodeService”, ”contentService” etc.  bypasses security check, audit and transaction checks.
Technically Alfresco uses AOP (Aspect-Oriented Programming) to expose services as “AOP proxies”.


To prove that, let’s go through publicly exposed services and some core services such as nodeService and contentService:

  1. https://svn.alfresco.com/repos/alfresco-open-mirror/alfresco/COMMUNITYTAGS/V5.0.d/root/projects/repository/config/alfresco/public-services-context.xml
  2. https://svn.alfresco.com/repos/alfresco-open-mirror/alfresco/COMMUNITYTAGS/V5.0.d/root/projects/repository/config/alfresco/content-services-context.xml
  3. https://svn.alfresco.com/repos/alfresco-open-mirror/alfresco/COMMUNITYTAGS/V5.0.d/root/projects/repository/config/alfresco/node-services-context.xml

content-services-context.xml
<bean id="contentService" parent="baseContentService">
                <property name="store">
                   <ref bean="fileContentStore"/>
                </property>
</bean>

node-services-context.xml
<bean id="nodeService" class="org.springframework.aop.framework.ProxyFactoryBean">
                <!--  Lazy init to avoid circular dependencies  -->
                <property name="targetSource">
                                <bean class="org.alfresco.config.NonBlockingLazyInitTargetSource">
                                                <property name="targetBeanName">
                                                                <idref bean="_nodeService"/>
                                                </property>
                                </bean>
                </property>
                <property name="proxyInterfaces">
                                <list>
                                                <value>org.alfresco.service.cmr.repository.NodeService</value>
                                </list>
                </property>
</bean>

Note: you can look into the xml files for more details.
public-services-context.xml
<!--  Public Node Service  -->
<bean id="NodeService" class="org.springframework.aop.framework.ProxyFactoryBean">
                <property name="proxyInterfaces">
                                <list>
                                    <value>org.alfresco.service.cmr.repository.NodeService</value>
                                </list>
                </property>
                <property name="target">
                                <ref bean="nodeService"/>
                </property>
                <property name="interceptorNames">
                                <list>
                                                <idref local="NodeService_transaction"/>
                                                <idref local="AuditMethodInterceptor"/>
                                                <idref local="exceptionTranslator"/>
                                                <idref bean="NodeService_security"/>
                                                <idref bean="disableAuditablePolicySetPropertyInterceptor"/>
                                </list>
                </property>
</bean>

<!--  Public Content Service  -->
<bean id="ContentService" class="org.springframework.aop.framework.ProxyFactoryBean">
                <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>

Notice that, the property ‘interceptorNames’ which has list of interceptors, which force the execution of transaction check (ContentService_transaction), audit (AuditMethodInterceptor) and security check (ContentService_security) etc.

So when you directly call the “contentService” (lower case), all these check are bypassed.
This can leads to security issue because alfresco will not evaluate the security before running the corresponding service operation in this case. So, it is best practice to use upper case services always.


Saturday, September 19, 2015

08 is not a valid integer in Java


In Java an integer beginning with 0 is treated as an octal (base 8).
If we write numbers with more than one significant digit we might be confused by the result.
Octal numbers can only use digits 0-7, like decimal can use 0-9 and binary can use 0-1.


For example:

010 = = 8
024 = = 20

So we should always take care to never begin an integer with 0.

You can refer to 'http://docs.oracle.com/javase/specs/jls/se8/jls8.pdf' page no. 28. It says "An octal numeral consists of an ASCII digit 0 followed by one or more of the ASCII digits 0 through 7 interspersed with underscores, and can represent a positive, zero, or negative integer"