/* * LinShare is an open source filesharing software, part of the LinPKI software * suite, developed by Linagora. * * Copyright (C) 2015 LINAGORA * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version, provided you comply with the Additional Terms applicable for * LinShare software by Linagora pursuant to Section 7 of the GNU Affero General * Public License, subsections (b), (c), and (e), pursuant to which you must * notably (i) retain the display of the “LinShare™” trademark/logo at the top * of the interface window, the display of the “You are using the Open Source * and free version of LinShare™, powered by Linagora © 2009–2015. Contribute to * Linshare R&D by subscribing to an Enterprise offer!” infobox and in the * e-mails sent with the Program, (ii) retain all hypertext links between * LinShare and linshare.org, between linagora.com and Linagora, and (iii) * refrain from infringing Linagora intellectual property rights over its * trademarks and commercial brands. Other Additional Terms apply, see * <http://www.linagora.com/licenses/> for more details. * * This program 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 Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License and * its applicable Additional Terms for LinShare along with this program. If not, * see <http://www.gnu.org/licenses/> for the GNU Affero General Public License * version 3 and <http://www.linagora.com/licenses/> for the Additional Terms * applicable to LinShare software. */ package org.linagora.linshare.cmis.service.impl; import java.io.File; import java.io.InputStream; import java.math.BigInteger; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.GregorianCalendar; import java.util.LinkedList; import java.util.List; import org.apache.chemistry.opencmis.commons.PropertyIds; import org.apache.chemistry.opencmis.commons.data.ContentStream; import org.apache.chemistry.opencmis.commons.data.ExtensionsData; import org.apache.chemistry.opencmis.commons.data.ObjectData; import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData; import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList; import org.apache.chemistry.opencmis.commons.data.ObjectParentData; import org.apache.chemistry.opencmis.commons.data.Properties; import org.apache.chemistry.opencmis.commons.data.RepositoryInfo; import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition; import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList; import org.apache.chemistry.opencmis.commons.enums.BaseTypeId; import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships; import org.apache.chemistry.opencmis.commons.enums.VersioningState; import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectDataImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderDataImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderListImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectParentDataImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl; import org.apache.chemistry.opencmis.commons.impl.server.ObjectInfoImpl; import org.apache.chemistry.opencmis.commons.server.ObjectInfo; import org.apache.chemistry.opencmis.commons.spi.Holder; import org.linagora.linshare.cmis.constants.CmisConstants; import org.linagora.linshare.cmis.constants.CmisDirectory; import org.linagora.linshare.cmis.constants.CmisStrings; import org.linagora.linshare.cmis.exceptions.CmisExceptionMappingService; import org.linagora.linshare.cmis.utils.CmisHelpers; import org.linagora.linshare.core.domain.constants.SupportedLanguage; import org.linagora.linshare.core.domain.entities.Account; import org.linagora.linshare.core.domain.entities.Thread; import org.linagora.linshare.core.domain.entities.ThreadEntry; import org.linagora.linshare.core.domain.entities.User; import org.linagora.linshare.core.exception.BusinessException; import org.linagora.linshare.core.service.ThreadEntryService; import org.linagora.linshare.core.service.ThreadService; import org.linagora.linshare.core.service.WorkGroupFolderService; import org.linagora.linshare.mongo.entities.WorkGroupFolder; public class ThreadEntryCmisServiceImpl extends EntryCmisServiceImpl { private final ThreadEntryService threadEntryService; private final CmisExceptionMappingService cmisExceptionMappingService; private final ThreadService threadService; private final CmisStrings cmisStrings; private final CmisHelpers helpers; private final WorkGroupFolderService workGroupFolderService; public ThreadEntryCmisServiceImpl(ThreadEntryService threadEntryService, WorkGroupFolderService workGroupFolderService, CmisExceptionMappingService cmisExceptionMappingService, ThreadService threadService, CmisStrings cmisStrings, CmisHelpers cmisHelpers) { super(); this.threadEntryService = threadEntryService; this.workGroupFolderService = workGroupFolderService; this.cmisExceptionMappingService = cmisExceptionMappingService; this.threadService = threadService; this.cmisStrings = cmisStrings; this.helpers = cmisHelpers; } private String computeThreadName(Account actor, Thread thread) { DateFormat dateFormat = new SimpleDateFormat( "MM-dd-yyyy_HH'h'mm'm'ss's'"); String res = cmisStrings.getName(CmisDirectory.THREAD, SupportedLanguage.fromTapestryLocale(actor.getCmisLocale())) + thread.getName() + "_" + dateFormat.format(thread.getCreationDate()); return res; } // CMIS: not use because this function is for repository. @Override public List<RepositoryInfo> getRepositoryInfos(ExtensionsData extension) { return null; } // CMIS: not use because this function is for repository. @Override public TypeDefinitionList getTypeChildren(String repositoryId, String typeId, Boolean includePropertyDefinitions, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) { return null; } // CMIS: not use because this function is for repository. @Override public TypeDefinition getTypeDefinition(String repositoryId, String typeId, ExtensionsData extension) { return null; } @Override public ObjectInFolderList getChildren(String repositoryId, String folderId, String filter, String orderBy, Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter, Boolean includePathSegment, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) { Account actor = helpers.prepare(repositoryId, true, false); ObjectInFolderList res = null; if (folderId.equals(CmisConstants.tagThread)) { res = getThreadList(actor); } else if (folderId.startsWith(CmisConstants.tagThreadChildren)) { res = getEntriesInThread(folderId, actor); } else throw new CmisObjectNotFoundException(); return res; } private ObjectInFolderList getEntriesInThread(String folderId, Account actor) { List<ObjectInFolderData> objDlist = new LinkedList<ObjectInFolderData>(); ObjectInFolderListImpl objList = new ObjectInFolderListImpl(); String threadId = helpers.getObjectUuid(folderId); Thread thread = threadService.find(actor, actor, threadId); List<ThreadEntry> entries; try { entries = threadEntryService.findMoreRecentByName(actor, thread); } catch (BusinessException e) { throw cmisExceptionMappingService.map(e); } for (ThreadEntry entry : entries) { ObjectInFolderDataImpl objData = new ObjectInFolderDataImpl( getObject(actor.getLsUuid(), CmisConstants.tagThreadEntry + entry.getUuid(), null, null, null, null, null, null, null)); objDlist.add(objData); } objList.setObjects(objDlist); return objList; } private ObjectInFolderList getThreadList(Account actor) { List<ObjectInFolderData> objDlist = new LinkedList<ObjectInFolderData>(); ObjectInFolderListImpl objList = new ObjectInFolderListImpl(); List<Thread> threads = threadService.findAllWhereAdmin((User) actor); for (Thread thread : threads) { ObjectInFolderDataImpl objData = new ObjectInFolderDataImpl( getObject(actor.getLsUuid(), CmisConstants.tagThreadChildren + thread.getLsUuid(), null, null, null, null, null, null, null)); objDlist.add(objData); } objList.setObjects(objDlist); return objList; } @Override public List<ObjectParentData> getObjectParents(String repositoryId, String objectId, String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter, Boolean includeRelativePathSegment, ExtensionsData extension) { Account actor = helpers.prepare(repositoryId, true, false); ThreadEntry entry = null; try { entry = threadEntryService .find(actor, actor, helpers.getObjectUuid(objectId)); } catch (BusinessException e) { throw cmisExceptionMappingService.map(e); } ObjectParentDataImpl opd = new ObjectParentDataImpl(getObject( repositoryId, CmisConstants.tagThreadChildren + entry.getEntryOwner().getLsUuid(), filter, includeAllowableActions, includeRelationships, renditionFilter, false, false, extension)); opd.setRelativePathSegment(entry.getName()); List<ObjectParentData> list = new LinkedList<ObjectParentData>(); list.add(opd); return list; } @Override public ObjectData getObject(String repositoryId, String objectId, String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds, Boolean includeAcl, ExtensionsData extension) { Account actor = helpers.prepare(repositoryId, true, false); ObjectDataImpl res = new ObjectDataImpl(); if (objectId.equals(CmisConstants.tagThread)) { String name = cmisStrings .getName(CmisDirectory.MY_THREADS, SupportedLanguage .fromTapestryLocale(actor.getCmisLocale())); String path = "/" + name; PropertiesImpl properties = helpers.setEntryProperty( objectId, path, name); res.setProperties(properties); } else if (objectId.startsWith(CmisConstants.tagThreadChildren)) { Thread thread = threadService .find(actor, actor, helpers.getObjectUuid(objectId)); String name = computeThreadName(actor, thread); String path = "/" + cmisStrings.getName(CmisDirectory.MY_THREADS, SupportedLanguage.fromTapestryLocale(actor .getCmisLocale())) + "/" + name; res.setProperties(helpers.setEntryProperty(objectId, path, name)); } else { ThreadEntry threadEntry = null; try { String threadUuid = helpers.getObjectUuid(objectId); threadEntry = threadEntryService.find(actor, actor, threadUuid); } catch (BusinessException e) { throw cmisExceptionMappingService.map(e); } PropertiesImpl properties = helpers.setAllPropertyToEntry(actor, objectId, threadEntry, threadEntry.getType(), threadEntry.getSize()); res.setProperties(properties); } res.setAllowableActions(helpers.setEntryAllowableActions( actor, objectId)); return res; } @Override public ContentStream getContentStream(String repositoryId, String objectId, String streamId, BigInteger offset, BigInteger length, ExtensionsData extension) { Account actor = helpers.prepare(repositoryId, true, false); ThreadEntry threadEntry; InputStream inputStream; try { threadEntry = threadEntryService.find(actor, actor, helpers.getObjectUuid(objectId)); inputStream = threadEntryService.getDocumentStream(actor, actor, threadEntry.getUuid()); } catch (BusinessException e) { throw cmisExceptionMappingService.map(e); } ContentStream res = new ContentStreamImpl(threadEntry.getName(), BigInteger.valueOf(threadEntry.getSize()), threadEntry.getType(), inputStream); return res; } @Override public ObjectInfo getObjectInfo(String repositoryId, String objectId) { Account actor = helpers.prepare(repositoryId, true, false); ObjectInfoImpl res; if (objectId.equals(CmisConstants.tagThread) || objectId.startsWith(CmisConstants.tagThreadChildren)) { res = new ObjectInfoImpl(objectId, BaseTypeId.CMIS_FOLDER); res.setObject(getObject(repositoryId, objectId, null, null, null, null, null, null, null)); } else { if (!objectId.startsWith(CmisConstants.tagThreadEntry)) { throw new CmisObjectNotFoundException(); } ThreadEntry threadEntry = null; try { threadEntry = threadEntryService.find(actor, actor, helpers.getObjectUuid(objectId)); } catch (BusinessException e) { throw cmisExceptionMappingService.map(e); } res = new ObjectInfoImpl(objectId, BaseTypeId.CMIS_DOCUMENT); res.setContentType(threadEntry.getType()); User user = (User) actor; res.setCreatedBy(user.getFirstName() + " " + user.getLastName()); res.setCreationDate((GregorianCalendar) threadEntry.getCreationDate()); res.setFileName(threadEntry.getName()); res.setLastModificationDate((GregorianCalendar) threadEntry .getDocument().getCreationDate()); res.setObject(getObject(repositoryId, objectId, null, null, null, null, null, null, null)); } return res; } @Override public void deleteObjectOrCancelCheckOut(String repositoryId, String objectId, Boolean allVersions, ExtensionsData extension) { Account actor = helpers.prepare(repositoryId, true, false); try { ThreadEntry threadEntry = threadEntryService.find(actor, actor, helpers.getObjectUuid(objectId)); threadEntryService.deleteThreadEntry(actor, actor, threadEntry); } catch (BusinessException e) { throw cmisExceptionMappingService.map(e); } } @Override public String create(String repositoryId, Properties properties, String folderId, ContentStream contentStream, VersioningState versioningState, List<String> policies, ExtensionsData extension) { Account actor = helpers.prepare(repositoryId, true, false); String res = folderId; if (contentStream.getFileName() != null) { Thread thread = null; File tempFile = null; thread = threadService.find(actor, actor, helpers.getObjectUuid(folderId)); try { tempFile = getTempFile(contentStream.getStream(), contentStream.getFileName()); ThreadEntry threadEntry = threadEntryService.createThreadEntry( actor, actor, thread, tempFile, contentStream.getFileName()); // TODO FIXME Business code outside service ! WorkGroupFolder folder = workGroupFolderService.addEntry(actor, (User)actor, thread, null, threadEntry); return CmisConstants.tagThreadEntry + threadEntry.getUuid(); } catch (BusinessException e) { throw cmisExceptionMappingService.map(e); } finally { deleteTempFile(tempFile); } } return res; } @Override public void updateProperties(String repositoryId, Holder<String> objectId, Holder<String> changeToken, Properties properties, ExtensionsData extension) { Account actor = helpers.prepare(repositoryId, true, false); String uuid = helpers.getObjectUuid(objectId.getValue()); String description = (String) properties.getProperties() .get(PropertyIds.DESCRIPTION).getFirstValue(); String name = (String) properties.getProperties().get(PropertyIds.NAME) .getFirstValue(); try { threadEntryService.updateFileProperties(actor, actor, uuid, description, null, name); } catch (BusinessException e) { throw cmisExceptionMappingService.map(e); } } // CMIS -> This method is never used. @Override public ObjectData getObjectByPath(String repositoryId, String path, String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds, Boolean includeAcl, ExtensionsData extension) { return null; } }