2 Replies Latest reply: Jan 17, 2013 8:41 AM by 971922 RSS

    Adding and downloading process attachments with Oracle BPM API

    971922
      I'm developing a web service interface for the BPM packages of the Oracle BPM API to handle process instance operations, as the Human Workflow Services only handles task operations.

      The Oracle BPM API Javadoc: http://docs.oracle.com/cd/E23943_01/apirefs.1111/e25378/

      The part I'm having problems is with process instance attachments, I get a null from getContent and getInputStream from IProcessAttachment whenever I call getProcessAttachments or getProcessInstance.getAttachment from the InstanceQueryService.

      Maybe the problem might be when I'm adding attachments in the first place; the code for adding attachment is based on Oracle's ATeam Custom Worklist example, specifically from http://java.net/projects/bpmworklist/sources/worklist/content/trunk/src/main/java/com/oracle/ateam/domain/MTaskList.java?rev=115#L377, addAttachment method at line 377.

      The example above is for task attachments, I adapted it for process instance attachments:
      Oracle BPM API imports:
      
      import oracle.bpel.services.bpm.common.IBPMContext;
      import oracle.bpel.services.workflow.task.model.ObjectFactory;
      import oracle.bpm.services.common.exception.BPMException;
      import oracle.bpm.services.instancemanagement.model.IProcessAttachment;
      import oracle.bpm.services.instancemanagement.model.IProcessInstance;
      import oracle.bpm.services.instancemanagement.model.impl.ProcessAttachment;
      
      (...)
      
      public @WebResult(name = "attachment")
      Attachment addAttachment(@WebParam(name = "context") BPMContext context,
                @WebParam(name = "instanceId") String instanceId,
                @WebParam(name = "attachment") Attachment attachment)
                throws BPMFault {
      
           try {
                // Creates a concrete oracle.bpel.services.workflow.verification.impl.WorkflowContext
                // as there's a bug in the API where it casts to it explicitly.
                IBPMContext ctx = (IBPMContext) context.toWorkflowContext();
      
                IProcessInstance processInstance = getInstanceQueryService().getProcessInstance(ctx, instanceId);
      
                IProcessAttachment processAttachment = new ProcessAttachment(new ObjectFactory().createAttachment()); 
      
                processAttachment.setName(attachment.getName());
                 
                // content is a String.
                // impl: this.content = content; 
                processAttachment.setContent(attachment.getContent());
                
                // getInputStream's impl:
                // return org.apache.commons.io.IOUtils.toInputStream(this.content);
                processAttachment.setInputStream(attachment.getInputStream());
                
                // processAttachment.getInputStream() does return the correct content at this point.
                
                processAttachment.setMimeType(attachment.getMimeType());
                processAttachment.setDescription(attachment.getDescription());
      
                return new Attachment(getInstanceManagementService().addAttachment(ctx, processInstance, processAttachment));
           } catch (BPMException e) {
                throw new BPMFault(e);
           } catch (Throwable t) {
                t.printStackTrace();
                throw new BPMFault(t);
           }
      }
      
      public @WebResult(name = "attachment")
      Attachment getProcessAttachment(
                @WebParam(name = "context") BPMContext context,
                @WebParam(name = "instanceId") String instanceId,
                @WebParam(name = "name") String attachmentName) throws BPMFault {
      
           try {
                IBPMContext ctx = (IBPMContext) context.toWorkflowContext();
      
                IProcessInstance processInstance = getInstanceQueryService().getProcessInstance(ctx, instanceId);
      
                // Either this processInstance or getInstanceQueryService().getProcessAttachment
                // return the same IProcessAttachment objects with a null inputStream.
                
                if (processInstance.getAttachment() != null) {
      
                     for (Object processAttachmentObj : processInstance.getAttachment()) {
      
                          IProcessAttachment processAttachment = (IProcessAttachment) processAttachmentObj;
      
                          if (attachmentName.equals(processAttachment.getName())) {
      
                               Attachment attachment = new Attachment(processAttachment);
                               
                               // loadContentFrom's impl:
                               // this.content = IOUtils.toString(processAttachment.getInputStream());
                               //
                               // NPEs because getInputStream returns null.
                               attachment.loadContentFrom(processAttachment);
                               return attachment;
                          }
                     }
                }
      
                return null;
      
           } catch (BPMException e) {
                throw new BPMFault(e);
           } catch (Throwable t) {
                t.printStackTrace();
                throw new BPMFault(t);
           }
      }
      What is the correct way to add and download attachments to a process instance using this API?
        • 1. Re: Adding and downloading process attachments with Oracle BPM API
          971922
          <font color="red">Edit: this method has problems connecting to the database to download attachments. Use the code in the next post below.</font>



          What I've learned:

          It seems Oracle BPM stores process-wide objects in one of the tasks inside the process (it may change in future versions). This task can be retrieved with the following code:
          IProcessInstance processInstance = getInstanceQueryService().getProcessInstance(ctx, instanceId);
          Task task = ((oracle.bpm.services.instancemanagement.model.impl.ProcessInstance) processInstance).getTask();
          Then to get the attachment contents
          import oracle.bpel.services.workflow.task.impl.WorkflowUtil;
          import oracle.bpel.services.workflow.task.model.AttachmentType;
          (...)
          String taskId = task.getSystemAttributes().getTaskId();
          AttachmentType attachmentType = WorkflowUtil.getAttachment(taskId, attachmentName);
          InputStream is = attachmentType.getInputStream();
          // process the inputStream.
          BTW, attachment.setInputStream is used to upload from a ServletInputStream, use attachment.setContent to upload from a String or base64-encoded(set IsContentEncoded to true) String source. Do not use inputStream and content at the same time.

          Edited by: bruno.laturner on Jan 17, 2013 6:42 AM
          • 2. Re: Adding and downloading process attachments with Oracle BPM API
            971922
            <font color="red">The method above has problems connecting to the database</font>


            The correct way to download attachments:
            IProcessInstance processInstance = getInstanceQueryService().getProcessInstance(ctx, instanceId);
            Task task = ((oracle.bpm.services.instancemanagement.model.impl.ProcessInstance) processInstance).getTask();
            String taskId = task.getSystemAttributes().getTaskId();
            int taskVersion = task.getSystemAttributes().getVersion();
            
            try {
              Transaction.start();
            
              AttachmentType attachmentType = Transaction.getPersistencyService().getAttachmentStream(taskId, taskVersion, attachmentName);
            
              //process attachmentType     .getInputStream()
            }
            // (catch code)
            finally {
              Transaction.close();
            }