/* * Copyright 2014 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jbpm.integration.cmis.impl; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.activation.MimetypesFileTypeMap; import org.apache.chemistry.opencmis.client.api.CmisObject; import org.apache.chemistry.opencmis.client.api.Document; import org.apache.chemistry.opencmis.client.api.DocumentType; import org.apache.chemistry.opencmis.client.api.Folder; import org.apache.chemistry.opencmis.client.api.ObjectId; import org.apache.chemistry.opencmis.client.api.Session; import org.apache.chemistry.opencmis.client.api.SessionFactory; import org.apache.chemistry.opencmis.client.runtime.SessionFactoryImpl; import org.apache.chemistry.opencmis.commons.PropertyIds; import org.apache.chemistry.opencmis.commons.SessionParameter; import org.apache.chemistry.opencmis.commons.data.ContentStream; import org.apache.chemistry.opencmis.commons.enums.BindingType; import org.apache.chemistry.opencmis.commons.enums.VersioningState; import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException; import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException; import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl; import org.jbpm.integration.cmis.UpdateMode; /** * Supporting class that provides helper method to interact with CMIS. * */ public abstract class OpenCMISSupport { /** * Creates new session to CMIS based on given connection details using ATOM binding * @param user * @param password * @param url * @param repository * @return */ protected Session getRepositorySession(String user, String password, String url, String repository) { SessionFactory factory = SessionFactoryImpl.newInstance(); Map<String, String> parameter = new HashMap<String, String>(); // user credentials parameter.put(SessionParameter.USER, user); parameter.put(SessionParameter.PASSWORD, password); // connection settings parameter.put(SessionParameter.ATOMPUB_URL, url); parameter.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value()); parameter.put(SessionParameter.REPOSITORY_ID, repository); // create session Session session = factory.createSession(parameter); return session; } /** * Finds folder by path and if not found returns null. * @param session * @param path * @return */ protected Folder findFolderForPath(Session session, String path) { try { return (Folder) session.getObjectByPath(path); } catch (CmisObjectNotFoundException e) { return null; } } /** * Finds Object (document or folder) by unique id. If not could exceptions is thrown * @param session * @param id * @return * @throws CmisObjectNotFoundException */ protected CmisObject findObjectForId(Session session, String id) { return session.getObject(id); } /** * Produces String representation of path elements * @param paths * @return */ protected String getPathAsString(List<String> paths) { if (paths == null || paths.isEmpty()) { return "/"; } StringBuffer buffer = new StringBuffer(); for (String path : paths) { buffer.append("/" + path); } return buffer.toString(); } /** * Returns last folder name from the path, if no available {root} * is returned. * @param parents * @return */ protected String getFolderName(List<Folder> parents) { if (parents == null || parents.isEmpty()) { return "{root}"; } return parents.get(parents.size() - 1).getName(); } /** * Creates folder under given parent, if parent is null the root folder is used as parent. * in case of nested folders entire path will be created. * @param session * @param parent * @param foldername * @return */ protected Folder createFolder(Session session, Folder parent, String foldername) { Folder root = parent; if (root == null) { root = session.getRootFolder(); } Folder newFolder = null; if (foldername.startsWith("/")) { foldername = foldername.substring(1); } StringBuffer currentPath = new StringBuffer(); String[] elems = foldername.split("/"); for (String folder : elems) { // properties // (minimal set: name and object type id) Map<String, Object> properties = new HashMap<String, Object>(); properties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder"); properties.put(PropertyIds.NAME, folder); currentPath.append("/" + folder); try { // create the folder newFolder = root.createFolder(properties); root = newFolder; } catch (CmisContentAlreadyExistsException e) { root = (Folder) session.getObjectByPath(currentPath.toString()); } } return newFolder; } /** * Creates document with given name, type and content inside the parent folder. If parent is null then * root folder is used. * @param session * @param parent * @param name * @param type * @param content * @return */ protected Document createDocument(Session session, Folder parent, String name, String type, byte[] content) { Folder root = parent; if (root == null) { root = session.getRootFolder(); } // properties // (minimal set: name and object type id) Map<String, Object> properties = new HashMap<String, Object>(); properties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document"); properties.put(PropertyIds.NAME, name); // set default type if none is given if (type == null) { type = "text/plain"; } // content try { InputStream input = new ByteArrayInputStream(content); ContentStream contentStream = new ContentStreamImpl(name, null, type, input); // create a major version Document newDoc = root.createDocument(properties, contentStream, VersioningState.MAJOR); input.close(); return newDoc; } catch (IOException e) { e.printStackTrace(); return null; } } /** * Updates document identified with objectId and type with given content accoring to the update mode. * @param session * @param objectId * @param type * @param content * @param mode * @return */ protected Document updateDocument(Session session, String objectId, String type, byte[] content, UpdateMode mode) { Document document = (Document) session.getObject(objectId); InputStream input = new ByteArrayInputStream(content); ContentStream contentStream = session.getObjectFactory().createContentStream(document.getName(), content.length, type, input); try { if (((DocumentType)(document.getType())).isVersionable() && (mode.equals(UpdateMode.MAJOR) || mode.equals(UpdateMode.MINOR))) { Document pwc = (Document) session.getObject(document.checkOut()); boolean major = mode.equals(UpdateMode.MAJOR); try { ObjectId newObjectId = pwc.checkIn(major, null, contentStream, "Document update from process"); return (Document) session.getObject(newObjectId); } catch (CmisBaseException e) { pwc.cancelCheckOut(); throw new RuntimeException("Cannot store document in CMIS reposiory", e); } } else if (mode.equals(UpdateMode.OVERRIDE)) { document.setContentStream(contentStream, true); } } finally { try { input.close(); } catch (IOException e) { // log it only } } return document; } /** * Deletes document identified by objectId. * @param session * @param objectId */ protected void deleteDocument(Session session, String objectId) { Document document = (Document) session.getObject(objectId); document.delete(false); } protected String getType(org.jbpm.document.Document document) { String type = document.getAttribute("type"); if (type == null || type.isEmpty()) { type = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(document.getName()); } return type; } protected String getLocation(org.jbpm.document.Document document) { String location = document.getAttribute("location"); if (location == null || location.isEmpty()) { location = "/"; } return location; } }