cancel
Showing results for 
Search instead for 
Did you mean: 

How do you access an uploaded file in a downstream service task?

jmulieri
Champ in-the-making
Champ in-the-making
I have a user task with a form that has a file upload field. In a separate java service task I would like to access the content of this file, or even just the path to the file on disk. For context… I am implementing a JavaDelegate, building a jar, and placing it in activiti-app/WEB-INF/lib. I can see the file on disk and I have tracked down some of the players, including: RelatedContentService and ContentStorage. I just can't seem to find a way to get a hold of these objects in my JavaDelegate. Any help on accessing the previously uploaded file is most appreciated.

Thanks!
Jon
8 REPLIES 8

jbarrez
Star Contributor
Star Contributor
only the db id is stored as process variable (for obvious performance reasons). You need to use the RelatedContentService to actually fetch the content wgen you need it.

jmulieri
Champ in-the-making
Champ in-the-making
Thank you for your reply. Can you help me understand how to use the RelatedContentService in my JavaDelegate? I have tried this but it is null when the execute method is called:

  @Autowired
  protected RelatedContentService contentService;

I am sure it is something simple that I am missing, just need a little direction to understand how things actually come together. Thanks!

jmulieri
Champ in-the-making
Champ in-the-making
I wanted to follow-up with my issue… to help someone in the future. I found a way to make this work, the gist of it is that you need to get a hold of the Spring application context to fetch the RelatedContentService bean. I tried various techniques for defining a bean with trying to auto wire in the dependencies with no success. So here is my workaround. I structured my code a little differently, and did the setup in my delegate's constructor, but for brevity, here is an example of a working execute method:

<java>
  public void execute(DelegateExecution execution) {
    try {
      String fileVariableName = "myfile"; // Id of 'upload file field' from form in previous User Task
      Class<?> theClass = Class.forName("com.activiti.conf.ApplicationConfiguration");
      AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(theClass);
      RelatedContentService relatedContentService = applicationContext.getBean(RelatedContentService.class);
      List<RelatedContent> contentList = relatedContentService.getFieldContentForProcessInstance(
          execution.getProcessInstanceId(), fileVariableName, 1, 0).getContent();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
  }
</java>

jbarrez
Star Contributor
Star Contributor
Can you posts your whole class, including package and all?

Are you sure it's in the right package, so it can be found by component scanning?

getting the application context is quite a heavy operation and shouldn't be needed.

jmulieri
Champ in-the-making
Champ in-the-making
Thanks Joram!

I finally cycled back around to this, and as I was putting together an example your comment was very helpful in clueing me to look into component scanning. That led me to the secret sauce… needing package com.activiti.extension.bean. Once I did that, the @Autowiring worked. I'm pasting in a working delegate for the next wandering soul…

<java>
package com.activiti.extension.bean;

import com.activiti.service.runtime.RelatedContentService;
import org.activiti.engine.delegate.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SomeActivitiDelegate implements JavaDelegate {

  @Autowired
  RelatedContentService relatedContentService;

  @Bean
  public SomeActivitiDelegate someActivitiDelegate() {
    return new SomeActivitiDelegate();
  }

  public void execute(DelegateExecution execution) {
    if (relatedContentService == null) {
      System.out.println("Source of great pain.");
    } else {
      System.out.println("Oh, sweet victory!");
    }
  }
}
</java>

Also, it is important to note that in order to use this, you must use the Delegate Expression property in your Service Task definition. In this example, setting the field to <code>${someActivitiDelegate}</code> did the trick.

kangkan
Champ in-the-making
Champ in-the-making

Hi,

thank you for your answer. I am new to alfresco.

I need some more help regarding this.

Let me be clear.

Suppose this upload file form. Its id is uploadurl

below is the method for execution listener.

@Override
public void notify(DelegateExecution arg0) throws Exception {

File f = new File("D:/some_file.zip");

// I want to get that zip file in f

 

}

Hope you got my question

jmulieri
Champ in-the-making
Champ in-the-making
Well… the saga continues… unfortunately, when using the above approach, I can't seem to be able to create RelatedContent. From within the execute method, if I call <java>relatedContentService.createRelatedContent(…)</java> the record is created but never committed. I can see in <java>AbstractPlatformTransactionManager.processCommit</java> the call to <java>doCommit(status)</java> is being skipped because it is not a new transaction. Do you know how I can get this record committed to the database? Missing the secret decoder ring again…

Update: While I am not exactly sure the subtleties at play, I was able to work through my issue. Apparently the transaction was not yet committed before a custom task I defined using AbstractBpmnActivityBehavior was invoked as the next task in the process. The AbstractBpmnActivityBehavior task was needing the related content, but was not finding it. I simply refactored the latter task to also be a class implementing JavaDelegate using the same approach with an @Autowired RelatedContentService as the SomeActvitiDelegate mentioned previously, and all was well.

jbarrez
Star Contributor
Star Contributor
Thanks for posting your solution. Many people googling towards here will appreciate it 🙂

Your analysis is correct: Activiti won't flush to the database until the transaction is committed. If you really want that, you can make your next task asynchronous.

Side remark: change @Configuration to @Component to be more correct (on your JavaDelegate).