cancel
Showing results for 
Search instead for 
Did you mean: 

How to call the node-service when my AMP starts up?

hbf
Champ on-the-rise
Champ on-the-rise
Hi!

My AMP preloads some data (the country tags that are currently in use, to be precise). I've first implemented "lazy caching" in the sense that the data is loaded/fetched only when some code asks for it.

This does not work however, as some client code is asking for the data within an afterCommit() handler. The result is

13:29:01,257 User:admin ERROR [repo.transaction.AlfrescoTransactionSupport] After completion (committed) listener exception: 
   listener: org.myorg.module.myapp.service.MyService@c937c8
org.alfresco.error.AlfrescoRuntimeException: onCommit cache modifications are not allowed.
   at org.alfresco.repo.cache.TransactionalCache.put(TransactionalCache.java:398)
   at org.alfresco.repo.ownable.impl.OwnableServiceImpl.getOwner(OwnableServiceImpl.java:144)
   at org.alfresco.repo.security.permissions.dynamic.OwnerDynamicAuthority.hasAuthority(OwnerDynamicAuthority.java:58)
   at org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.getAuthorisations(PermissionServiceImpl.java:447)
   at org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.hasPermission(PermissionServiceImpl.java:345)
   at org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.hasPermission(PermissionServiceImpl.java:577)
   at sun.reflect.GeneratedMethodAccessor266.invoke(Unknown Source)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:585)
   at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:281)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:187)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:154)
   at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:107)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
   at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:210)
   at $Proxy14.hasPermission(Unknown Source)

Therefore my question: What is the easiest way to run a few queries against the nodeService after AMP startup? I tried to do it from within my init-method="init" bean initialization method, but it seems no transaction is set up at this point yet.

Thanks for any hint,
Kaspar
4 REPLIES 4

claudio_martins
Champ in-the-making
Champ in-the-making
Please post your configuration files and your java classes, so we can have a look and may help you. Smiley Happy


Cheers, CM.

hbf
Champ on-the-rise
Champ on-the-rise
I've tried to isolate the problem a little further; here's the revised picture: I have an AMP (org.myorg.module.MyPackage) that preloads the category hierarchy for the countries (this is the standard "REGIONS" category hierarchy of Alfresco). I need to preload them because I need very fast access to them.

This AMP has the following configuration in my module's module-context.xml:

 <!– Instantiate the custom Service. –>
<bean id="myService" class="org.myorg.module.MyPackage.service.MyService" init-method="init">
  <property name="serviceRegistry">
   <ref bean="ServiceRegistry" />
  </property>
  <property name="policyComponent">
   <ref bean="policyComponent" />
  </property>
  <property name="dirRoot">
   <value>${dir.root}</value>
  </property>
</bean>

The class MyService has a method

  /**
   * Returns the list of all country categories. The first time you call this,
   * the list is actually fetched from the repository but cached afterwards, so that
   * subsequent calls are very fast.
   */
  public List<NodeRef> getCachedCountryHierarchy()
  {
    // …
    NodeRef tag = …;
    List<ChildAssociationRef> childAssocs = nodeService.getChildAssocs(tag); // (*)
    // …
  }

The important thing here is that this method calls NodeService's getChildAssocs() method.

Now comes the problem: Some *other* code uses my AMP and calls getCachedCountryHierarchy() from within a afterCommit() listener. If this is the first time (since Alfresco startup) that getCachedCountryHierarchy() gets called, the line (*) is executed, which results in the exception from the original post.

So it seems that I have to make sure that getCachedCountryHierarchy() is called after Alfresco startup. How can I do this?

I tried to do it in my service's init() method (see configuration above), by just calling getCachedCountryHierarchy() there. But at this point, no Alfresco transaction is set up and I get an authentication error, so I am wondering what the "standard" way is to perform tasks against the repository (queries in my case) after AMP startup. I think it's a general pattern that many AMPs will require, so I thought there's maybe a general way to do it…

Many thanks,
Kaspar

andy
Champ on-the-rise
Champ on-the-rise
Hi

Can you post the full stack trace to show how your code is getting called in the TX after commit. What is this "other" code?

Andy

stijndereede
Champ in-the-making
Champ in-the-making
I've got a sort of similar problem. I want to make sure that certain folders exist in the workspace, otherwise my module doesn't work correctly. So I'm looking for a way to execute some code after my module has been loaded when Alfresco starts.
The bean in my module-context.xml is:

   <bean id="module.cayman" class="org.alfresco.module.cayman.Main" parent="module.baseComponent" init-method="init">
      <property name="nodeService">
         <ref bean="NodeService" />
      </property>      
   </bean>
(Do I actually need to extend baseComponent?)
And the cayman.Main class is:

public class Main extends AbstractModuleComponent {
   private NodeService nodeService;
   public void setNodeService(NodeService nodeService) {
      this.nodeService = nodeService;
   }

   public void init() {
      System.out.println("Init of Cayman module");
      logger.debug("Init of Cayman module");
      
      StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
      NodeRef ref1 = new NodeRef(storeRef, "/app:company_home/cm:Cayman");
      System.out.println(nodeService.exists(ref1));
   }
}

Without the nodeService call the init() method gets executed, but with it I get:

17:53:58,241 ERROR [org.springframework.web.context.ContextLoader] Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'module.cayman' defined in file [D:\alfresco\tomcat\webapps\alfresco\WEB-INF\classes\alfresco\module\cayman\module-context.xml]: Invocation of init method failed; nested exception is net.sf.acegisecurity.AuthenticationCredentialsNotFoundException: A valid SecureContext was not provided in the RequestContext
Caused by: net.sf.acegisecurity.AuthenticationCredentialsNotFoundException: A valid SecureContext was not provided in the RequestContext
   at net.sf.acegisecurity.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:477)
   at net.sf.acegisecurity.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:355)
   at net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:77)

(and so on…)

See also my other post: http://forums.alfresco.com/viewtopic.php?t=11304

Regards,

Stijn


BTW: what is the correct (simple) way to check if a folder exists in the spacesstore if you know the path? Would the above actually work?