/*******************************************************************************
* Copyright (c) 2013 aegif.
*
* This file is part of NemakiWare.
*
* NemakiWare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NemakiWare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with NemakiWare.
* If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* linzhixing(https://github.com/linzhixing) - initial API and implementation
******************************************************************************/
package jp.aegif.nemaki.dao.impl.couch;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ektorp.Attachment;
import org.ektorp.AttachmentInputStream;
import org.ektorp.CouchDbConnector;
import org.ektorp.ViewQuery;
import org.ektorp.ViewResult;
import org.ektorp.ViewResult.Row;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jp.aegif.nemaki.cmis.factory.info.RepositoryInfoMap;
import jp.aegif.nemaki.dao.ContentDaoService;
import jp.aegif.nemaki.dao.impl.couch.connector.ConnectorPool;
import jp.aegif.nemaki.model.Archive;
import jp.aegif.nemaki.model.AttachmentNode;
import jp.aegif.nemaki.model.Change;
import jp.aegif.nemaki.model.Content;
import jp.aegif.nemaki.model.Document;
import jp.aegif.nemaki.model.Folder;
import jp.aegif.nemaki.model.Item;
import jp.aegif.nemaki.model.NemakiPropertyDefinitionCore;
import jp.aegif.nemaki.model.NemakiPropertyDefinitionDetail;
import jp.aegif.nemaki.model.NemakiTypeDefinition;
import jp.aegif.nemaki.model.NodeBase;
import jp.aegif.nemaki.model.Policy;
import jp.aegif.nemaki.model.Relationship;
import jp.aegif.nemaki.model.Rendition;
import jp.aegif.nemaki.model.VersionSeries;
import jp.aegif.nemaki.model.couch.CouchArchive;
import jp.aegif.nemaki.model.couch.CouchAttachmentNode;
import jp.aegif.nemaki.model.couch.CouchChange;
import jp.aegif.nemaki.model.couch.CouchContent;
import jp.aegif.nemaki.model.couch.CouchDocument;
import jp.aegif.nemaki.model.couch.CouchFolder;
import jp.aegif.nemaki.model.couch.CouchItem;
import jp.aegif.nemaki.model.couch.CouchNodeBase;
import jp.aegif.nemaki.model.couch.CouchPolicy;
import jp.aegif.nemaki.model.couch.CouchPropertyDefinitionCore;
import jp.aegif.nemaki.model.couch.CouchPropertyDefinitionDetail;
import jp.aegif.nemaki.model.couch.CouchRelationship;
import jp.aegif.nemaki.model.couch.CouchRendition;
import jp.aegif.nemaki.model.couch.CouchTypeDefinition;
import jp.aegif.nemaki.model.couch.CouchVersionSeries;
import jp.aegif.nemaki.util.constant.NodeType;
/**
* Dao Service implementation for CouchDB.
*
* @author linzhixing
*
*/
@Component
public class ContentDaoServiceImpl implements ContentDaoService {
private RepositoryInfoMap repositoryInfoMap;
private ConnectorPool connectorPool;
private static final Log log = LogFactory.getLog(ContentDaoServiceImpl.class);
private static final String DESIGN_DOCUMENT = "_design/_repo";
private static final String ATTACHMENT_NAME = "content";
public ContentDaoServiceImpl() {
}
// ///////////////////////////////////////
// Type & Property definition
// ///////////////////////////////////////
@Override
public List<NemakiTypeDefinition> getTypeDefinitions(String repositoryId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("typeDefinitions");
List<CouchTypeDefinition> l = connectorPool.get(repositoryId).queryView(query, CouchTypeDefinition.class);
if (CollectionUtils.isEmpty(l)) {
return null;
} else {
List<NemakiTypeDefinition> result = new ArrayList<NemakiTypeDefinition>();
for (CouchTypeDefinition ct : l) {
result.add(ct.convert());
}
return result;
}
}
@Override
public NemakiTypeDefinition getTypeDefinition(String repositoryId, String typeId) {
throw new UnsupportedOperationException(Thread.currentThread().getStackTrace()[0].getMethodName()
+ ":this method is only for cahced service. No need for implementation.");
}
@Override
public NemakiTypeDefinition createTypeDefinition(String repositoryId, NemakiTypeDefinition typeDefinition) {
CouchTypeDefinition ct = new CouchTypeDefinition(typeDefinition);
connectorPool.get(repositoryId).create(ct);
return ct.convert();
}
@Override
public NemakiTypeDefinition updateTypeDefinition(String repositoryId, NemakiTypeDefinition typeDefinition) {
CouchTypeDefinition cp = connectorPool.get(repositoryId).get(CouchTypeDefinition.class, typeDefinition.getId());
CouchTypeDefinition update = new CouchTypeDefinition(typeDefinition);
update.setRevision(cp.getRevision());
connectorPool.get(repositoryId).update(update);
return update.convert();
}
@Override
public void deleteTypeDefinition(String repositoryId, String nodeId) {
delete(repositoryId, nodeId);
}
@Override
public List<NemakiPropertyDefinitionCore> getPropertyDefinitionCores(String repositoryId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("propertyDefinitionCores");
List<CouchPropertyDefinitionCore> l = connectorPool.get(repositoryId)
.queryView(query, CouchPropertyDefinitionCore.class);
if (CollectionUtils.isEmpty(l)) {
return null;
} else {
List<NemakiPropertyDefinitionCore> result = new ArrayList<NemakiPropertyDefinitionCore>();
for (CouchPropertyDefinitionCore cpdc : l) {
result.add(cpdc.convert());
}
return result;
}
}
@Override
public NemakiPropertyDefinitionCore getPropertyDefinitionCore(String repositoryId, String nodeId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("propertyDefinitionCores").key(nodeId);
List<CouchPropertyDefinitionCore> l = connectorPool.get(repositoryId)
.queryView(query, CouchPropertyDefinitionCore.class);
if (CollectionUtils.isEmpty(l)) {
return null;
} else {
return l.get(0).convert();
}
}
@Override
public NemakiPropertyDefinitionCore getPropertyDefinitionCoreByPropertyId(String repositoryId, String propertyId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("propertyDefinitionCoresByPropertyId")
.key(propertyId);
List<CouchPropertyDefinitionCore> l = connectorPool.get(repositoryId)
.queryView(query, CouchPropertyDefinitionCore.class);
if (CollectionUtils.isEmpty(l)) {
return null;
} else {
return l.get(0).convert();
}
}
@Override
public NemakiPropertyDefinitionDetail getPropertyDefinitionDetail(String repositoryId, String nodeId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("propertyDefinitionDetails")
.key(nodeId);
List<CouchPropertyDefinitionDetail> l = connectorPool.get(repositoryId)
.queryView(query, CouchPropertyDefinitionDetail.class);
if (CollectionUtils.isEmpty(l)) {
return null;
} else {
return l.get(0).convert();
}
}
@Override
public List<NemakiPropertyDefinitionDetail> getPropertyDefinitionDetailByCoreNodeId(String repositoryId,
String coreNodeId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("propertyDefinitionDetailsByCoreNodeId")
.key(coreNodeId);
List<CouchPropertyDefinitionDetail> l = connectorPool.get(repositoryId)
.queryView(query, CouchPropertyDefinitionDetail.class);
if (CollectionUtils.isEmpty(l)) {
return null;
} else {
List<NemakiPropertyDefinitionDetail> result = new ArrayList<NemakiPropertyDefinitionDetail>();
for (CouchPropertyDefinitionDetail cpdd : l) {
result.add(cpdd.convert());
}
return result;
}
}
@Override
public NemakiPropertyDefinitionCore createPropertyDefinitionCore(String repositoryId,
NemakiPropertyDefinitionCore propertyDefinitionCore) {
CouchPropertyDefinitionCore cpc = new CouchPropertyDefinitionCore(propertyDefinitionCore);
connectorPool.get(repositoryId).create(cpc);
return cpc.convert();
}
@Override
public NemakiPropertyDefinitionDetail createPropertyDefinitionDetail(String repositoryId,
NemakiPropertyDefinitionDetail propertyDefinitionDetail) {
CouchPropertyDefinitionDetail cpd = new CouchPropertyDefinitionDetail(propertyDefinitionDetail);
connectorPool.get(repositoryId).create(cpd);
return cpd.convert();
}
@Override
public NemakiPropertyDefinitionDetail updatePropertyDefinitionDetail(String repositoryId,
NemakiPropertyDefinitionDetail propertyDefinitionDetail) {
CouchPropertyDefinitionDetail cpd = connectorPool.get(repositoryId)
.get(CouchPropertyDefinitionDetail.class, propertyDefinitionDetail.getId());
CouchPropertyDefinitionDetail update = new CouchPropertyDefinitionDetail(propertyDefinitionDetail);
update.setRevision(cpd.getRevision());
connectorPool.get(repositoryId).update(update);
return update.convert();
}
// ///////////////////////////////////////
// Content
// ///////////////////////////////////////
@Override
public NodeBase getNodeBase(String repositoryId, String objectId) {
CouchNodeBase cnb = connectorPool.get(repositoryId).get(CouchNodeBase.class, objectId);
return cnb.convert();
}
@Override
public Content getContent(String repositoryId, String objectId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("contentsById").key(objectId);
ViewResult result = connectorPool.get(repositoryId).queryView(query);
return convertJsonToEachBaeType(result);
}
private Content convertJsonToEachBaeType(ViewResult result) {
if (result.getRows().isEmpty()) {
return null;
} else {
Iterator<Row> iterator = result.getRows().iterator();
while (iterator.hasNext()) {
ObjectMapper mapper = new ObjectMapper();
JsonNode jn = iterator.next().getValueAsNode();
String baseType = jn.path("type").textValue();
if (BaseTypeId.CMIS_DOCUMENT.value().equals(baseType)) {
CouchDocument cd = mapper.convertValue(jn, CouchDocument.class);
return cd.convert();
} else if (BaseTypeId.CMIS_FOLDER.value().equals(baseType)) {
CouchFolder cf = mapper.convertValue(jn, CouchFolder.class);
return cf.convert();
} else if (BaseTypeId.CMIS_POLICY.value().equals(baseType)) {
CouchPolicy cp = mapper.convertValue(jn, CouchPolicy.class);
return cp.convert();
} else if (BaseTypeId.CMIS_RELATIONSHIP.value().equals(baseType)) {
CouchRelationship cr = mapper.convertValue(jn, CouchRelationship.class);
return cr.convert();
} else if (BaseTypeId.CMIS_ITEM.value().equals(baseType)) {
CouchItem ci = mapper.convertValue(jn, CouchItem.class);
return ci.convert();
}
}
}
return null;
}
// TODO Use view
@Override
public Document getDocument(String repositoryId, String objectId) {
CouchDocument cd = connectorPool.get(repositoryId).get(CouchDocument.class, objectId);
Document doc = cd.convert();
return doc;
}
@Override
public boolean existContent(String repositoryId, String objectTypeId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("countByObjectType").key(objectTypeId);
ViewResult l = connectorPool.get(repositoryId).queryView(query);
List<Row> rows = l.getRows();
if (CollectionUtils.isEmpty(rows)) {
return false;
} else {
for (Row row : rows) {
if (objectTypeId.equals(row.getKey())) {
int count = row.getValueAsInt();
if (count == 0) {
return false;
} else {
return true;
}
}
}
}
return false;
}
@Override
public List<Document> getCheckedOutDocuments(String repositoryId, String parentFolderId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("privateWorkingCopies");
if (parentFolderId != null)
query.key(parentFolderId);
List<CouchDocument> l = connectorPool.get(repositoryId).queryView(query, CouchDocument.class);
if (CollectionUtils.isEmpty(l))
return null;
List<Document> results = new ArrayList<Document>();
for (CouchDocument cd : l) {
results.add(cd.convert());
}
return results;
}
@Override
public VersionSeries getVersionSeries(String repositoryId, String nodeId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("versionSeries").key(nodeId);
List<CouchVersionSeries> l = connectorPool.get(repositoryId).queryView(query, CouchVersionSeries.class);
if (CollectionUtils.isEmpty(l)) {
return null;
} else {
return l.get(0).convert();
}
}
@Override
public List<Document> getAllVersions(String repositoryId, String versionSeriesId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("documentsByVersionSeriesId")
.key(versionSeriesId);
List<CouchDocument> cds = connectorPool.get(repositoryId).queryView(query, CouchDocument.class);
if (CollectionUtils.isEmpty(cds))
return null;
List<Document> list = new ArrayList<Document>();
for (CouchDocument cd : cds) {
list.add(cd.convert());
}
return list;
}
@Override
public Document getDocumentOfLatestVersion(String repositoryId, String versionSeriesId) {
if (versionSeriesId == null)
return null;
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("latestVersions").key(versionSeriesId);
List<CouchDocument> list = connectorPool.get(repositoryId).queryView(query, CouchDocument.class);
if (list.size() == 1) {
return list.get(0).convert();
} else if (list.size() > 1) {
log.warn("The latest version of [" + versionSeriesId + "] is duplicate.");
return list.get(0).convert();
} else {
return null;
}
}
@Override
public Document getDocumentOfLatestMajorVersion(String repositoryId, String versionSeriesId) {
if (versionSeriesId == null)
return null;
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("latestMajorVersions")
.key(versionSeriesId);
List<CouchDocument> list = connectorPool.get(repositoryId).queryView(query, CouchDocument.class);
if (list.size() == 1) {
return list.get(0).convert();
} else if (list.size() > 1) {
log.warn("The latest major version of [" + versionSeriesId + "] is duplicate.");
return list.get(0).convert();
} else {
return null;
}
}
@Override
public Folder getFolder(String repositoryId, String objectId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("folders").key(objectId);
List<CouchFolder> list = connectorPool.get(repositoryId).queryView(query, CouchFolder.class);
if (CollectionUtils.isEmpty(list)) {
return null;
} else {
return list.get(0).convert();
}
}
@Override
public Folder getFolderByPath(String repositoryId, String path) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("foldersByPath").key(path);
List<CouchFolder> l = connectorPool.get(repositoryId).queryView(query, CouchFolder.class);
if (CollectionUtils.isEmpty(l))
return null;
return l.get(0).convert();
}
@Override
public List<Content> getChildren(String repositoryId, String parentId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("children").key(parentId);
List<CouchContent> list = connectorPool.get(repositoryId).queryView(query, CouchContent.class);
if (list != null && !list.isEmpty()) {
List<Content> contents = new ArrayList<Content>();
for (CouchContent cc : list) {
contents.add(cc.convert());
}
return contents;
} else {
return null;
}
}
@Override
public Content getChildByName(String repositoryId, String parentId, String name) {
class ViewKey {
private String parentId;
private String name;
public ViewKey(String parentId, String name) {
this.parentId = parentId;
this.name = name;
}
public String getParentId() {
return parentId;
}
public String getName() {
return name;
}
}
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("childByName")
.key(new ViewKey(parentId, name));
ViewResult result = connectorPool.get(repositoryId).queryView(query);
return convertJsonToEachBaeType(result);
}
public List<String> getChildrenNames(String repositoryId, String parentId){
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("childrenNames")
.key(parentId);
ViewResult result = connectorPool.get(repositoryId).queryView(query);
List<String>list = new ArrayList<String>();
if(result == null || result.isEmpty()){
return new ArrayList<String>();
}else{
Iterator<Row> itr = result.iterator();
while(itr.hasNext()){
list.add(itr.next().getValue());
}
}
return list;
}
@Override
public Relationship getRelationship(String repositoryId, String objectId) {
CouchRelationship cr = connectorPool.get(repositoryId).get(CouchRelationship.class, objectId);
return cr.convert();
}
@Override
public List<Relationship> getRelationshipsBySource(String repositoryId, String sourceId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("relationshipsBySource").key(sourceId);
List<CouchRelationship> crs = connectorPool.get(repositoryId).queryView(query, CouchRelationship.class);
List<Relationship> result = new ArrayList<Relationship>();
if (crs != null && !crs.isEmpty()) {
for (CouchRelationship cr : crs) {
result.add(cr.convert());
}
}
return result;
}
@Override
public List<Relationship> getRelationshipsByTarget(String repositoryId, String targetId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("relationshipsByTarget").key(targetId);
List<CouchRelationship> crs = connectorPool.get(repositoryId).queryView(query, CouchRelationship.class);
List<Relationship> result = new ArrayList<Relationship>();
if (crs != null && !crs.isEmpty()) {
for (CouchRelationship cr : crs) {
result.add(cr.convert());
}
}
return result;
}
@Override
public Policy getPolicy(String repositoryId, String objectId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("policies").key(objectId);
List<CouchPolicy> cps = connectorPool.get(repositoryId).queryView(query, CouchPolicy.class);
if (!CollectionUtils.isEmpty(cps)) {
return cps.get(0).convert();
} else {
return null;
}
}
@Override
public List<Policy> getAppliedPolicies(String repositoryId, String objectId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("policiesByAppliedObject")
.key(objectId);
List<CouchPolicy> cps = connectorPool.get(repositoryId).queryView(query, CouchPolicy.class);
if (!CollectionUtils.isEmpty(cps)) {
List<Policy> policies = new ArrayList<Policy>();
for (CouchPolicy cp : cps) {
policies.add(cp.convert());
}
return policies;
} else {
return null;
}
}
@Override
public Item getItem(String repositoryId, String objectId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("items").key(objectId);
List<CouchItem> cpi = connectorPool.get(repositoryId).queryView(query, CouchItem.class);
if (!CollectionUtils.isEmpty(cpi)) {
return cpi.get(0).convert();
} else {
return null;
}
}
@Override
public Document create(String repositoryId, Document document) {
CouchDocument cd = new CouchDocument(document);
connectorPool.get(repositoryId).create(cd);
return cd.convert();
}
@Override
public VersionSeries create(String repositoryId, VersionSeries versionSeries) {
CouchVersionSeries cvs = new CouchVersionSeries(versionSeries);
connectorPool.get(repositoryId).create(cvs);
return cvs.convert();
}
@Override
public Folder create(String repositoryId, Folder folder) {
CouchFolder cf = new CouchFolder(folder);
connectorPool.get(repositoryId).create(cf);
return cf.convert();
}
@Override
public Relationship create(String repositoryId, Relationship relationship) {
CouchRelationship cr = new CouchRelationship(relationship);
connectorPool.get(repositoryId).create(cr);
return cr.convert();
}
@Override
public Policy create(String repositoryId, Policy policy) {
CouchPolicy cp = new CouchPolicy(policy);
connectorPool.get(repositoryId).create(cp);
return cp.convert();
}
@Override
public Item create(String repositoryId, Item item) {
CouchItem ci = new CouchItem(item);
connectorPool.get(repositoryId).create(ci);
return ci.convert();
}
@Override
public Document update(String repositoryId, Document document) {
CouchDocument cd = connectorPool.get(repositoryId).get(CouchDocument.class, document.getId());
// Set the latest revision for avoid conflict
CouchDocument update = new CouchDocument(document);
update.setRevision(cd.getRevision());
connectorPool.get(repositoryId).update(update);
return update.convert();
}
@Override
public Document move(String repositoryId, Document document, String sourceId){
return update(repositoryId, document);
}
@Override
public VersionSeries update(String repositoryId, VersionSeries versionSeries) {
CouchVersionSeries cvs = connectorPool.get(repositoryId).get(CouchVersionSeries.class, versionSeries.getId());
// Set the latest revision for avoid conflict
CouchVersionSeries update = new CouchVersionSeries(versionSeries);
update.setRevision(cvs.getRevision());
connectorPool.get(repositoryId).update(update);
return update.convert();
}
@Override
public Folder update(String repositoryId, Folder folder) {
CouchFolder cf = connectorPool.get(repositoryId).get(CouchFolder.class, folder.getId());
// Set the latest revision for avoid conflict
CouchFolder update = new CouchFolder(folder);
update.setRevision(cf.getRevision());
connectorPool.get(repositoryId).update(update);
return update.convert();
}
@Override
public Folder move(String repositoryId, Folder folder, String sourceId){
return update(repositoryId, folder);
}
@Override
public Relationship update(String repositoryId, Relationship relationship) {
CouchRelationship cp = connectorPool.get(repositoryId).get(CouchRelationship.class, relationship.getId());
// Set the latest revision for avoid conflict
CouchRelationship update = new CouchRelationship(relationship);
update.setRevision(cp.getRevision());
connectorPool.get(repositoryId).update(update);
return update.convert();
}
@Override
public Policy update(String repositoryId, Policy policy) {
CouchPolicy cp = connectorPool.get(repositoryId).get(CouchPolicy.class, policy.getId());
// Set the latest revision for avoid conflict
CouchPolicy update = new CouchPolicy(policy);
update.setRevision(cp.getRevision());
connectorPool.get(repositoryId).update(update);
return update.convert();
}
@Override
public Item update(String repositoryId, Item item) {
CouchItem ci = connectorPool.get(repositoryId).get(CouchItem.class, item.getId());
// Set the latest revision for avoid conflict
CouchItem update = new CouchItem(item);
update.setRevision(ci.getRevision());
connectorPool.get(repositoryId).update(update);
return update.convert();
}
@Override
public void delete(String repositoryId, String objectId) {
CouchNodeBase cnb = connectorPool.get(repositoryId).get(CouchNodeBase.class, objectId);
connectorPool.get(repositoryId).delete(cnb);
}
// ///////////////////////////////////////
// Attachment
// ///////////////////////////////////////
@Override
public AttachmentNode getAttachment(String repositoryId, String attachmentId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("attachments").key(attachmentId);
List<CouchAttachmentNode> list = connectorPool.get(repositoryId).queryView(query, CouchAttachmentNode.class);
if (CollectionUtils.isEmpty(list)) {
return null;
} else {
CouchAttachmentNode can = list.get(0);
Attachment a = can.getAttachments().get(ATTACHMENT_NAME);
AttachmentNode an = new AttachmentNode();
an.setId(can.getId());
an.setMimeType(a.getContentType());
an.setLength(a.getContentLength());
return an;
}
}
@Override
public void setStream(String repositoryId, AttachmentNode attachmentNode) {
AttachmentInputStream ais = connectorPool.get(repositoryId)
.getAttachment(attachmentNode.getId(), ATTACHMENT_NAME);
attachmentNode.setInputStream(ais);
}
@Override
public Rendition getRendition(String repositoryId, String objectId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("renditions").key(objectId);
List<CouchRendition> list = connectorPool.get(repositoryId).queryView(query, CouchRendition.class);
if (CollectionUtils.isEmpty(list)) {
return null;
} else {
CouchRendition crd = list.get(0);
Attachment a = crd.getAttachments().get(ATTACHMENT_NAME);
Rendition rd = new Rendition();
rd.setId(objectId);
rd.setTitle(crd.getTitle());
rd.setKind(crd.getKind());
rd.setMimetype(a.getContentType());
rd.setLength(a.getContentLength());
AttachmentInputStream ais = connectorPool.get(repositoryId).getAttachment(objectId, ATTACHMENT_NAME);
rd.setInputStream(ais);
/*
* try { BufferedImage bimg = ImageIO.read(ais); if (bimg != null) {
* rd.setWidth(bimg.getWidth()); rd.setHeight(bimg.getHeight());
* bimg.flush(); } } catch (IOException e) { // TODO logging // do
* nothing }
*/
return rd;
}
}
@Override
public String createAttachment(String repositoryId, AttachmentNode attachment, ContentStream contentStream) {
CouchAttachmentNode ca = new CouchAttachmentNode(attachment);
connectorPool.get(repositoryId).create(ca);
AttachmentInputStream ais = new AttachmentInputStream(ATTACHMENT_NAME, contentStream.getStream(), contentStream
.getMimeType(), contentStream.getLength());
connectorPool.get(repositoryId).createAttachment(ca.getId(), ca.getRevision(), ais);
return ca.getId();
}
@Override
public String createRendition(String repositoryId, Rendition rendition, ContentStream contentStream) {
CouchRendition cr = new CouchRendition(rendition);
connectorPool.get(repositoryId).create(cr);
AttachmentInputStream ais = new AttachmentInputStream(ATTACHMENT_NAME, contentStream.getStream(), contentStream
.getMimeType(), contentStream.getLength());
connectorPool.get(repositoryId).createAttachment(cr.getId(), cr.getRevision(), ais);
return cr.getId();
}
@Override
public void updateAttachment(String repositoryId, AttachmentNode attachment, ContentStream contentStream) {
CouchAttachmentNode ca = connectorPool.get(repositoryId).get(CouchAttachmentNode.class, attachment.getId());
CouchAttachmentNode update = new CouchAttachmentNode(attachment);
// Set the latest revision for avoid conflict
update.setRevision(ca.getRevision());
String revisionAfterDeleted = connectorPool.get(repositoryId)
.deleteAttachment(ca.getId(), ca.getRevision(), ATTACHMENT_NAME);
AttachmentInputStream ais = new AttachmentInputStream(ATTACHMENT_NAME, contentStream.getStream(), contentStream
.getMimeType());
connectorPool.get(repositoryId).createAttachment(attachment.getId(), revisionAfterDeleted, ais);
}
// ///////////////////////////////////////
// Change event
// ///////////////////////////////////////
@Override
public Change getChangeEvent(String repositoryId, String changeTokenId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("changesByToken").key(changeTokenId);
List<CouchChange> l = connectorPool.get(repositoryId).queryView(query, CouchChange.class);
if (CollectionUtils.isEmpty(l))
return null;
return l.get(0).convert();
}
@Override
public Change getLatestChange(String repositoryId) {
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("changesByToken").descending(true)
.limit(1);
List<CouchChange> l = connectorPool.get(repositoryId).queryView(query, CouchChange.class);
if (CollectionUtils.isEmpty(l)) {
return null;
} else {
return l.get(0).convert();
}
}
@Override
public List<Change> getLatestChanges(String repositoryId, String startToken, int maxItems) {
List<Change> result = new ArrayList<Change>();
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("changesByToken").descending(false);
if (StringUtils.isNotBlank(startToken)) {
CouchDbConnector conn = connectorPool.get(repositoryId);
try {
CouchChange startChange = conn.get(CouchChange.class, startToken);
Long startKey = startChange.getToken();
query.startKey(startKey);
} catch (org.ektorp.DocumentNotFoundException ex) {
return null;
}
}
if (maxItems > 0) {
query.limit(maxItems);
}
List<CouchChange> l = connectorPool.get(repositoryId).queryView(query, CouchChange.class);
if (CollectionUtils.isEmpty(l))
return null;
for (CouchChange cc : l) {
result.add(cc.convert());
}
return result;
}
@Override
public Change create(String repositoryId, Change change) {
CouchChange cc = new CouchChange(change);
connectorPool.get(repositoryId).create(cc);
return cc.convert();
}
// ///////////////////////////////////////
// Archive
// ///////////////////////////////////////
@Override
public Archive getArchive(String repositoryId, String objectId) {
String archive = repositoryInfoMap.getArchiveId(repositoryId);
CouchArchive ca = connectorPool.get(archive).get(CouchArchive.class, objectId);
return ca.convert();
}
@Override
public Archive getArchiveByOriginalId(String repositoryId, String originalId) {
String archive = repositoryInfoMap.getArchiveId(repositoryId);
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("all").key(originalId);
List<CouchArchive> list = connectorPool.get(archive).queryView(query, CouchArchive.class);
if (list != null && !list.isEmpty()) {
return list.get(0).convert();
} else {
return null;
}
}
@Override
public Archive getAttachmentArchive(String repositoryId, Archive archive) {
String archiveId = repositoryInfoMap.getArchiveId(repositoryId);
if (!archive.isDocument())
return null;
String attachmentId = archive.getAttachmentNodeId();
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("attachments").key(attachmentId);
List<CouchArchive> list = connectorPool.get(archiveId).queryView(query, CouchArchive.class);
if (list != null && !list.isEmpty()) {
return list.get(0).convert();
} else {
return null;
}
}
@Override
public List<Archive> getChildArchives(String repositoryId, Archive archive) {
String archiveId = repositoryInfoMap.getArchiveId(repositoryId);
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("children")
.key(archive.getOriginalId());
List<CouchArchive> list = connectorPool.get(archiveId).queryView(query, CouchArchive.class);
if (list != null && !list.isEmpty()) {
List<Archive> archives = new ArrayList<Archive>();
for (CouchArchive ca : list) {
archives.add(ca.convert());
}
return archives;
} else {
return null;
}
}
@Override
public List<Archive> getArchivesOfVersionSeries(String repositoryId, String versionSeriesId) {
String archiveId = repositoryInfoMap.getArchiveId(repositoryId);
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("versionSeries").key(versionSeriesId);
List<CouchArchive> list = connectorPool.get(archiveId).queryView(query, CouchArchive.class);
if (list != null && !list.isEmpty()) {
List<Archive> archives = new ArrayList<Archive>();
for (CouchArchive ca : list) {
archives.add(ca.convert());
}
return archives;
} else {
return null;
}
}
@Override
public List<Archive> getAllArchives(String repositoryId) {
String archiveId = repositoryInfoMap.getArchiveId(repositoryId);
ViewQuery query = new ViewQuery().designDocId(DESIGN_DOCUMENT).viewName("all");
List<CouchArchive> list = connectorPool.get(archiveId).queryView(query, CouchArchive.class);
List<Archive> archives = new ArrayList<Archive>();
for (CouchArchive ca : list) {
archives.add(ca.convert());
}
return archives;
}
@Override
public Archive createArchive(String repositoryId, Archive archive, Boolean deletedWithParent) {
String archiveId = repositoryInfoMap.getArchiveId(repositoryId);
CouchNodeBase cnb = connectorPool.get(repositoryId).get(CouchNodeBase.class, archive.getOriginalId());
CouchArchive ca = new CouchArchive(archive);
ca.setLastRevision(cnb.getRevision());
// Write to DB
connectorPool.get(archiveId).create(ca);
return ca.convert();
}
@Override
public Archive createAttachmentArchive(String repositoryId, Archive archive) {
String archiveId = repositoryInfoMap.getArchiveId(repositoryId);
CouchArchive ca = new CouchArchive(archive);
CouchNodeBase cnb = connectorPool.get(repositoryId).get(CouchNodeBase.class, archive.getOriginalId());
ca.setLastRevision(cnb.getRevision());
connectorPool.get(archiveId).create(ca);
return ca.convert();
}
@Override
// FIXME return archiveId or something when successfully deleted
public void deleteArchive(String repositoryId, String archiveId) {
String archive = repositoryInfoMap.getArchiveId(repositoryId);
try {
CouchArchive ca = connectorPool.get(archive).get(CouchArchive.class, archiveId);
connectorPool.get(archive).delete(ca);
} catch (Exception e) {
log.warn(buildLogMsg(archiveId, "the archive not found on db"));
return;
}
}
@SuppressWarnings("deprecation")
@Override
public void restoreContent(String repositoryId, Archive archive) {
if (archive.isDocument()) {
// Restore a content
CouchDocument cd = connectorPool.get(repositoryId)
.get(CouchDocument.class, archive.getOriginalId(), archive.getLastRevision());
cd.setRevision(null);
connectorPool.get(repositoryId).update(cd);
} else if (archive.isFolder()) {
CouchFolder cf = connectorPool.get(repositoryId)
.get(CouchFolder.class, archive.getOriginalId(), archive.getLastRevision());
cf.setRevision(null);
connectorPool.get(repositoryId).update(cf);
} else {
// TODO Do nothing?
}
}
@SuppressWarnings("deprecation")
@Override
public void restoreAttachment(String repositoryId, Archive archive) {
CouchDbConnector connector = connectorPool.get(repositoryId);
// Restore its attachment
CouchAttachmentNode can = connector
.get(CouchAttachmentNode.class, archive.getOriginalId(), archive.getLastRevision());
can.setRevision(null);
AttachmentInputStream is = connector.getAttachment(can.getId(), ATTACHMENT_NAME, archive.getLastRevision());
connector.createAttachment(can.getId(), can.getRevision(), is);
CouchAttachmentNode restored = connector.get(CouchAttachmentNode.class, can.getId());
restored.setType(NodeType.ATTACHMENT.value());
connector.update(restored);
}
// ///////////////////////////////////////
// Other
// ///////////////////////////////////////
private String buildLogMsg(String objectId, String msg) {
return "[objectId:" + objectId + "]" + msg;
}
public void setConnectorPool(ConnectorPool connectorPool) {
this.connectorPool = connectorPool;
}
public void setRepositoryInfoMap(RepositoryInfoMap repositoryInfoMap) {
this.repositoryInfoMap = repositoryInfoMap;
}
@Override
public void refreshCmisObjectData(String repositoryId, String objectId) {
// this method is for cached service
}
}