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.
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.