/*
* 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.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import org.apache.chemistry.opencmis.client.api.Folder;
import org.apache.chemistry.opencmis.client.api.Session;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.commons.io.IOUtils;
import org.drools.core.common.DroolsObjectInputStream;
import org.jbpm.document.Document;
import org.jbpm.integration.cmis.UpdateMode;
import org.kie.api.marshalling.ObjectMarshallingStrategy;
/**
* ObjectMarshallingStrategy implementation for storing and retrieving data from CMIS compatible systems.
* It will act only on variables that are of type <code>Document</code>
* It allows to specify connection details to the repository
* <ul>
* <li>user</li>
* <li>password</li>
* <li>url</li>
* <li>repository</li>
* </ul>
* and uses ATOM binding to connect and interact with CMIS. On top of that update mode can also be selected - override,
* new major version, new minor version on update. By default override mode is used if none is specified.
* <br/>
* Interaction with CMIS can be done with one of the following ways:
* <ul>
* <li>create new document based on variable - to do so Document variable should have null objectId and must have content</li>
* <li>update document based on variable - to do so Document variable must have objectId set and must have content</li>
* <li>read document from CMIS - to do so Document variable must have only objectId set and other fields left empty</li>
* </ul>
* Every time a document is updated it might get new objectId and thus it will be set upon such operations.
*
* @see Document
*/
public class OpenCMISPlaceholderResolverStrategy extends OpenCMISSupport implements ObjectMarshallingStrategy {
private String user;
private String password;
private String url;
private String repository;
private String contentUrl;
private UpdateMode mode = UpdateMode.OVERRIDE;
public OpenCMISPlaceholderResolverStrategy(String user, String password, String url, String repository) {
this.user = user;
this.password = password;
this.url = url;
this.repository = repository;
}
public OpenCMISPlaceholderResolverStrategy(String user, String password, String url, String repository, UpdateMode mode) {
this.user = user;
this.password = password;
this.url = url;
this.repository = repository;
this.mode = mode;
}
public OpenCMISPlaceholderResolverStrategy(String user, String password, String url, String repository, String contentUrl) {
this.user = user;
this.password = password;
this.url = url;
this.repository = repository;
this.contentUrl = contentUrl;
}
public OpenCMISPlaceholderResolverStrategy(String user, String password, String url, String repository, String contentUrl, UpdateMode mode) {
this.user = user;
this.password = password;
this.url = url;
this.repository = repository;
this.contentUrl = contentUrl;
this.mode = mode;
}
public boolean accept(Object object) {
if (object instanceof Document) {
return true;
}
return false;
}
public byte[] marshal(Context context, ObjectOutputStream os, Object object) throws IOException {
Document document = (Document) object;
Session session = getRepositorySession(user, password, url, repository);
try {
if (document.getContent() != null) {
String type = getType(document);
if (document.getIdentifier() == null || document.getIdentifier().isEmpty()) {
String location = getLocation(document);
Folder parent = findFolderForPath(session, location);
if (parent == null) {
parent = createFolder(session, null, location);
}
org.apache.chemistry.opencmis.client.api.Document doc = createDocument(session, parent, document.getName(), type, document.getContent());
document.setIdentifier(doc.getId());
document.addAttribute("updated", "true");
} else {
if (document.getContent() != null && "true".equals(document.getAttribute("updated"))) {
org.apache.chemistry.opencmis.client.api.Document doc = updateDocument(session, document.getIdentifier(), type, document.getContent(), mode);
document.setIdentifier(doc.getId());
document.addAttribute("updated", "false");
}
}
}
ByteArrayOutputStream buff = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream( buff );
oos.writeUTF(document.getIdentifier());
oos.writeUTF(object.getClass().getCanonicalName());
oos.close();
return buff.toByteArray();
} finally {
session.clear();
}
}
public Object unmarshal(Context context, ObjectInputStream ois, byte[] object, ClassLoader classloader) throws IOException, ClassNotFoundException {
DroolsObjectInputStream is = new DroolsObjectInputStream( new ByteArrayInputStream( object ), classloader );
String objectId = is.readUTF();
String canonicalName = is.readUTF();
Session session = getRepositorySession(user, password, url, repository);
try {
org.apache.chemistry.opencmis.client.api.Document doc = (org.apache.chemistry.opencmis.client.api.Document) findObjectForId(session, objectId);
Document document = (Document) Class.forName(canonicalName).newInstance();
document.setAttributes(new HashMap<String, String>());
document.setIdentifier(objectId);
document.setName(doc.getName());
document.setLastModified(doc.getLastModificationDate().getTime());
document.setSize(doc.getContentStreamLength());
document.addAttribute("location", getFolderName(doc.getParents()) + getPathAsString(doc.getPaths()));
if (doc.getContentStream() != null && contentUrl == null) {
ContentStream stream = doc.getContentStream();
document.setContent(IOUtils.toByteArray(stream.getStream()));
document.addAttribute("updated", "false");
document.addAttribute("type", stream.getMimeType());
} else {
document.setLink(contentUrl + document.getIdentifier());
}
return document;
} catch(Exception e) {
throw new RuntimeException("Cannot read document from CMIS", e);
} finally {
is.close();
session.clear();
}
}
public Context createContext() {
return null;
}
/*
* for backward compatibility with previous serialization mechanism - before protobuf was used
* (non-Javadoc)
* @see org.kie.api.marshalling.ObjectMarshallingStrategy#write(java.io.ObjectOutputStream, java.lang.Object)
* @see org.kie.api.marshalling.ObjectMarshallingStrategy#read(java.io.ObjectOutputStream)
*/
public void write(ObjectOutputStream os, Object object) throws IOException {
Document document = (Document) object;
Session session = getRepositorySession(user, password, url, repository);
try {
if (document.getContent() != null) {
String type = document.getAttribute("type");
if (document.getIdentifier() == null) {
String location = document.getAttribute("location");
Folder parent = findFolderForPath(session, location);
if (parent == null) {
parent = createFolder(session, null, location);
}
org.apache.chemistry.opencmis.client.api.Document doc = createDocument(session, parent, document.getName(), type, document.getContent());
document.setIdentifier(doc.getId());
document.addAttribute("updated", "false");
} else {
if (document.getContent() != null && "true".equals(document.getAttribute("updated"))) {
org.apache.chemistry.opencmis.client.api.Document doc = updateDocument(session, document.getIdentifier(), type, document.getContent(), mode);
document.setIdentifier(doc.getId());
document.addAttribute("updated", "false");
}
}
}
ByteArrayOutputStream buff = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream( buff );
oos.writeUTF(document.getIdentifier());
oos.writeUTF(object.getClass().getCanonicalName());
oos.close();
} finally {
session.clear();
}
}
public Object read(ObjectInputStream os) throws IOException, ClassNotFoundException {
String objectId = os.readUTF();
String canonicalName = os.readUTF();
Session session = getRepositorySession(user, password, url, repository);
try {
org.apache.chemistry.opencmis.client.api.Document doc = (org.apache.chemistry.opencmis.client.api.Document) findObjectForId(session, objectId);
Document document = (Document) Class.forName(canonicalName).newInstance();
document.setIdentifier(objectId);
document.setName(doc.getName());
document.addAttribute("location", getFolderName(doc.getParents()) + getPathAsString(doc.getPaths()));
if (doc.getContentStream() != null) {
ContentStream stream = doc.getContentStream();
document.setContent(IOUtils.toByteArray(stream.getStream()));
document.addAttribute("updated", "false");
document.addAttribute("type", stream.getMimeType());
}
return document;
} catch(Exception e) {
throw new RuntimeException("Cannot read document from CMIS", e);
} finally {
session.clear();
}
}
}