How To Upload A Document For A Task to design your custom ECM using BPM API as a RESTful service.
This guide provides instructions on how to Upload a document for a task to design your custom ECM using BPM API as a Restful Service.
Applies to:
This Document Holds good for all CE 7.3 SP05 onwards. This service can be called from UI5 Screen as an Ajax call.
Summary:
This guide describes step-by-step how to upload a document for a Task to design custom ECM using BPM API as a rest full service.
About Me:
As a Sr. Netweaver Consultant, I’ve been undertaking consulting assignments leveraging on my undermentioned NetWeaver skills.
- Business Process Management (SAP NW BPM)
- Restful Services using BPM api to be used in UI5 Screens.
- SAP Web Dynpro Java (SAP WD4J)
- SAP Business Rules Management (SAP BRMS)
- SAP Composit Application Framework (SAP CAF)
- Master Data Management (SAP NW MDM)
- Enterprise Portal (SAP EP)
- Services creation using NWDS (SAP EJB)
- Enterprise SOA
Prerequisites:
You should have read through the document :How to Start a BPM Process using BPM API as a RESTful service.
We will be discussing following points in detail in this document –
- Adding Libraries.
- Setting up the foundation for using Libraries.
- Creating Deploy-able Object.
- Accessing the methods exposed.
Adding Libraries:
Step 1 : Refer the document to add libraries.
Setting up the foundation for using Library:
Step 1 : Create a new DC of type “Web Module”.
Step 2 : Define a dependency between the Web Module and the library DC. Add only the “api” public part from the External library DC to the Web module DC.
Step 3 : Create 2 packages (1 for Business Objects, 1 for the Restful Services)
Step 4 : Create Business Objects as shown below:
import java.io.InputStream;
public class ECMFile {
private String id;
private String name;
private String type;
private String path;
private String url;
private long size;
InputStream file;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public InputStream getFile() {
return file;
}
public void setFile(InputStream file) {
this.file = file;
}
}
public class FileDto {
String folderId = null;
String documentId = null;
byte[] file = null;
public String getDocumentId() {
return documentId;
}
public void setDocumentId(String documentId) {
this.documentId = documentId;
}
public String getFolderId() {
return folderId;
}
public void setFolderId(String folderId) {
this.folderId = folderId;
}
public byte[] getFile() {
return file;
}
public void setFile(byte[] file) {
this.file = file;
}
}
Step 5.1 : Create a ECM Document Service class file and write a code as shown below:
package rest.converter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.cxf.helpers.IOUtils;
import bo.ECMFile;
import bo.FileDto;
import com.sap.ecm.Application;
import com.sap.ecm.Ecm;
import com.sap.ecm.exceptions.EcmException;
import com.sap.ecm.item.File;
import com.sap.ecm.item.Folder;
import com.sap.ecm.item.Node;
import com.sap.ecm.item.Property;
import com.sap.ecm.item.value.Content;
import com.sap.ecm.item.value.Value;
import com.sap.ecm.name.EcmName;
import com.sap.ecm.name.Path;
import com.sap.ecm.repository.Repository;
import com.sap.ecm.repository.Session;
import com.sap.security.api.IUser;
import com.sap.security.api.UMException;
import com.sap.security.api.UMFactory;
import com.sap.tc.webdynpro.clientserver.uielib.standard.api.WDFileDownloadBehaviour;
import com.sap.tc.webdynpro.progmodel.api.WDResourceFactory;
import com.sap.tc.webdynpro.services.sal.datatransport.api.IWDResource;
import com.sap.tc.webdynpro.services.sal.url.api.WDWebResourceType;
public class ECMDocumentService {
protected static final String THE_NAMESPACE = "http://sap.com/reuse/attachment_properties";
private static final String ECM_FACTORY_PROPERTY = "ecm/default";
private Context ctx;
private Ecm ecm;
private Folder rootFolder;
private static final String rootFolderPath = "/BPM_Attachments"; // The folder in which you want to put the document.
private Application application;
private Session session;
private Node rootNode;
public ArrayList<String> uploadDocument(FileDto fileDto)
{
ArrayList<String> fileNameList = new ArrayList<String>();
try
{
ctx = new InitialContext();
ecm = (Ecm) ctx.lookup(Ecm.JNDI_LOOKUP_KEY);
IUser usr = UMFactory.getUserFactory().getUserByLogonID("Administrator");
EcmName ecmName = EcmName.get("", "default");
application = ecm.connect(ecmName);
Repository repository = application.getRepository(ecmName);
session = repository.login(repository.getCredentials(usr));
rootNode = session.getWorkspace().getNode(Path.getPath(rootFolderPath));
rootFolder = (Folder) rootNode;
boolean folderExists = false;
for (Node currentNode : rootFolder.getChildren())
{
if ((currentNode) instanceof Folder && currentNode.getName().equals(fileDto.getFolderId()))
{
rootFolder = (Folder) currentNode;
System.err.println("Folder already exists : "+rootFolder.getName());
folderExists = true;
break;
}
}
if (!folderExists)
{
rootFolder = rootFolder.createFolder(fileDto.getFolderId());
System.err.println("Folder created : "+rootFolder.getName());
}
Value value = session.getValueFactory().createValue(fileDto.getDocumentId());
List<Property> props = new ArrayList<Property>();
props.add(session.getValueFactory().createProperty(ecmName, value));
// write file
long size = -1;
ByteArrayInputStream bais = new ByteArrayInputStream(fileDto.getFile());
File file = rootFolder.createFile(fileDto.getDocumentId(), null, props, bais, null, size);
System.err.println("File uploaded :"+file.getName());
} catch(EcmException e) {
System.err.println("EcmException : "+e.getMessage());
} catch (NamingException e) {
System.err.println("NamingException : "+e.getMessage());
} catch (UMException e) {
System.err.println("UMException : "+e.getMessage());
}
finally //cleanup
{
cleanupECMSession();
}
return fileNameList;
}
public FileDto downloadDocument(String requestId)
{
List<ECMFile> files = getFolderContent(requestId);
if(files.size() == 0)
return null;
FileDto fileDto = new FileDto();
ECMFile ecmFile = files.get(0);
if(ecmFile != null)
{
try
{
byte[] bytes = IOUtils.readBytesFromStream(ecmFile.getFile());
fileDto.setDocumentId(ecmFile.getName());
fileDto.setFile(bytes);
}
catch (IOException e)
{
System.err.println("IOException : "+e.getLocalizedMessage());
}
}
return fileDto;
}
public List<ECMFile> getFolderContent(String folderId)
{
List<ECMFile> files = new ArrayList<ECMFile>();
if(folderId == null || folderId.trim().length() == 0)
return null;
try
{
IUser usr = UMFactory.getUserFactory().getUserByLogonID("Administrator");
Context ctx = new InitialContext();
ecm = (Ecm) ctx.lookup(Ecm.JNDI_LOOKUP_KEY);
application = ecm.connect("","");
Repository repository = application.getRepository(EcmName.get("", "default")) ;
session = repository.login(repository.getCredentials(usr));
Node root = session.getWorkspace().getNode(com.sap.ecm.name.Path.getPath("/BPM_Attachments/PRC_"+folderId));
List<Node> children = ((Folder) root).getChildren();
for (Node child:children)
{
if (child instanceof File)
{
File file = (File)child;
ECMFile ecmFile = new ECMFile();
Content content = file.getContent();
ecmFile.setId(file.getId());
ecmFile.setName(file.getName());
ecmFile.setPath(file.getPath().toString());
ecmFile.setSize(content.getSize());
ecmFile.setType(content.getType());
ecmFile.setFile(content.getStream());
ecmFile.setUrl(content.getContentURL());
files.add(ecmFile);
}
}
}catch(EcmException e) {
System.err.println("EcmException : "+e.getMessage());
} catch (NamingException e) {
System.err.println("NamingException : "+e.getMessage());
} catch (UMException e) {
System.err.println("UMException : "+e.getMessage());
}
finally //cleanup
{
cleanupECMSession();
}
return files;
}
private void cleanupECMSession()
{
if (session != null)
{
session.logout();
}
if (ecm != null)
{
try
{
ecm.disconnect(application);
}
catch (Exception e)
{
System.err.println("Exception : "+e.getMessage());
}
}
}
}
Step 5.2 : Create a restful service class file and write a code as shown below or if you are continuing from the document then just copy past the methods only:
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URI;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.activation.DataHandler;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.cxf.jaxrs.ext.multipart.Attachment;
import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import bo.FileDto;
import bo.Material;
import bo.MaterialCreation;
import bo.TaskHeader;
import bo.TaskHeaders;
import com.sap.bpm.api.BPMFactory;
import com.sap.bpm.exception.api.BPMException;
import com.sap.bpm.pm.api.ProcessDefinition;
import com.sap.bpm.pm.api.ProcessDefinitionManager;
import com.sap.bpm.pm.api.ProcessInstance;
import com.sap.bpm.pm.api.ProcessInstanceManager;
import com.sap.bpm.pm.api.ProcessStartEvent;
import com.sap.bpm.pm.api.ProcessStartManager;
import com.sap.bpm.tm.api.Status;
import com.sap.bpm.tm.api.TaskAbstract;
import com.sap.bpm.tm.api.TaskDetail;
import com.sap.bpm.tm.api.TaskInstanceManager;
import com.sap.tc.logging.Location;
import commonj.sdo.DataObject;
import commonj.sdo.helper.XMLHelper;
@Path("/MaterialCreationService")
@Produces({MediaType.APPLICATION_XML})
public class MaterialCreationToRestService {
private static final Location location = Location.getLocation(MaterialCreationToRestService.class);
private final String PRE_TASK_URI = "bpm://bpm.sap.com/task-instance/";
@Path("/uploadDocument/{documentId}")
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public void uploadDocument(MultipartBody multipartBody, @javax.ws.rs.core.Context HttpServletRequest req,
@PathParam("documentId") String documentId) throws IOException
{
System.err.println("ECMDocumentService -> uploadDocument");
System.err.println("Document ID : "+documentId);
ECMDocumentService ecmDocumentService = new ECMDocumentService();
String filename = extractFilenameFromContentDisposition(multipartBody.getAllAttachments().get(0).getContentDisposition().toString());
System.err.println("File Name : "+filename);
if(documentId == null || documentId.trim().length() == 0)
return;
String folderId = getProcessInstanceForTaskInstance(documentId);
System.err.println("Folder ID : "+folderId);
if(folderId == null || folderId.trim().length() == 0)
return;
List<Attachment> attachments = multipartBody.getAllAttachments();
DataHandler dataHandler = attachments.get(0).getDataHandler();
InputStream is = dataHandler.getInputStream();
byte[] bArray = new byte[is.available()];
is.read(bArray);
FileDto fileDto = new FileDto();
fileDto.setFolderId("PRC_"+folderId);
fileDto.setDocumentId(filename);
fileDto.setFile(bArray);
ecmDocumentService.uploadDocument(fileDto);
}
private String extractFilenameFromContentDisposition(String requestString)
{
if(requestString == null || requestString.trim().length() == 0)
return requestString;
String fileName = null;
Pattern regex = Pattern.compile("(?<=filename=\").*?(?=\")");
Matcher regexMatcher = regex.matcher(requestString);
if (regexMatcher.find()) {
fileName = regexMatcher.group();
}
return fileName;
}
private String getProcessInstanceForTaskInstance(String taskInstanceId)
{
System.err.println("ArticleMaintenanceService -> getTaskDetails");
System.err.println("Task Instance ID: "+taskInstanceId);
try
{
URI taskInstId = new URI("bpm://bpm.sap.com/task-instance/" + taskInstanceId);
ProcessInstanceManager processInstanceManager = BPMFactory.getProcessInstanceManager();
ProcessInstance processInstance = processInstanceManager.getProcessInstanceForTaskInstanceId(taskInstId);
String processInstanceId = extractID(processInstance.getId().toString());
System.err.println("Process Instance ID : "+processInstanceId);
return processInstanceId;
}
catch (Exception e)
{
System.err.println("Exception : "+e.getMessage());
}
return null;
}
private String extractID(String instanceId)
{
if(instanceId == null || instanceId.trim().length() == 0)
return instanceId;
String [] ids = instanceId.split("/");
return ids[ids.length-1];
}
}
Step 6 & Step 7 is same as mentioned in the document. If you are continuing then you can ignore these steps.
Creating Deploy-able Object & Accessing the methods exposed.
Refer the document to “Creating Deploy-able Object” & “Accessing the methods exposed” as it is the same.
The next part of this document is : How to Download A Document From the custom ECM for a process using BPM API as a RESTful service.