001/* 002 * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Antoine Taillefer <ataillefer@nuxeo.com> 016 */ 017package org.nuxeo.drive.adapter.impl; 018 019import static org.nuxeo.ecm.platform.query.nxql.CoreQueryDocumentPageProvider.CORE_SESSION_PROPERTY; 020 021import java.io.IOException; 022import java.io.Serializable; 023import java.util.ArrayList; 024import java.util.HashMap; 025import java.util.List; 026import java.util.Map; 027 028import org.nuxeo.drive.adapter.FileItem; 029import org.nuxeo.drive.adapter.FileSystemItem; 030import org.nuxeo.drive.adapter.FolderItem; 031import org.nuxeo.ecm.core.api.Blob; 032import org.nuxeo.ecm.core.api.CoreInstance; 033import org.nuxeo.ecm.core.api.CoreSession; 034import org.nuxeo.ecm.core.api.DocumentModel; 035import org.nuxeo.ecm.core.api.NuxeoException; 036import org.nuxeo.ecm.core.api.security.SecurityConstants; 037import org.nuxeo.ecm.platform.filemanager.api.FileManager; 038import org.nuxeo.ecm.platform.query.api.PageProvider; 039import org.nuxeo.ecm.platform.query.api.PageProviderService; 040import org.nuxeo.runtime.api.Framework; 041 042/** 043 * {@link DocumentModel} backed implementation of a {@link FolderItem}. 044 * 045 * @author Antoine Taillefer 046 */ 047public class DocumentBackedFolderItem extends AbstractDocumentBackedFileSystemItem implements FolderItem { 048 049 private static final long serialVersionUID = 1L; 050 051 private static final String FOLDER_ITEM_CHILDREN_PAGE_PROVIDER = "FOLDER_ITEM_CHILDREN"; 052 053 protected boolean canCreateChild; 054 055 public DocumentBackedFolderItem(String factoryName, DocumentModel doc) { 056 this(factoryName, doc, false); 057 } 058 059 public DocumentBackedFolderItem(String factoryName, DocumentModel doc, boolean relaxSyncRootConstraint) { 060 super(factoryName, doc, relaxSyncRootConstraint); 061 initialize(doc); 062 } 063 064 public DocumentBackedFolderItem(String factoryName, FolderItem parentItem, DocumentModel doc) { 065 this(factoryName, parentItem, doc, false); 066 } 067 068 public DocumentBackedFolderItem(String factoryName, FolderItem parentItem, DocumentModel doc, 069 boolean relaxSyncRootConstraint) { 070 super(factoryName, parentItem, doc, relaxSyncRootConstraint); 071 initialize(doc); 072 } 073 074 protected DocumentBackedFolderItem() { 075 // Needed for JSON deserialization 076 } 077 078 /*--------------------- FileSystemItem ---------------------*/ 079 @Override 080 public void rename(String name) { 081 try (CoreSession session = CoreInstance.openCoreSession(repositoryName, principal)) { 082 // Update doc properties 083 DocumentModel doc = getDocument(session); 084 doc.setPropertyValue("dc:title", name); 085 doc = session.saveDocument(doc); 086 session.save(); 087 // Update FileSystemItem attributes 088 this.docTitle = name; 089 this.name = name; 090 updateLastModificationDate(doc); 091 } 092 } 093 094 /*--------------------- FolderItem -----------------*/ 095 @Override 096 @SuppressWarnings("unchecked") 097 public List<FileSystemItem> getChildren() { 098 try (CoreSession session = CoreInstance.openCoreSession(repositoryName, principal)) { 099 PageProviderService pageProviderService = Framework.getLocalService(PageProviderService.class); 100 Map<String, Serializable> props = new HashMap<String, Serializable>(); 101 props.put(CORE_SESSION_PROPERTY, (Serializable) session); 102 PageProvider<DocumentModel> childrenPageProvider = (PageProvider<DocumentModel>) pageProviderService.getPageProvider( 103 FOLDER_ITEM_CHILDREN_PAGE_PROVIDER, null, null, 0L, props, docId); 104 Long pageSize = childrenPageProvider.getPageSize(); 105 106 List<FileSystemItem> children = new ArrayList<FileSystemItem>(); 107 int nbChildren = 0; 108 boolean reachedPageSize = false; 109 boolean hasNextPage = true; 110 // Since query results are filtered, make sure we iterate on PageProvider to get at most its page size 111 // number of 112 // FileSystemItems 113 while (nbChildren < pageSize && hasNextPage) { 114 List<DocumentModel> dmChildren = childrenPageProvider.getCurrentPage(); 115 for (DocumentModel dmChild : dmChildren) { 116 FileSystemItem child = getFileSystemItemAdapterService().getFileSystemItem(dmChild, this); 117 if (child != null) { 118 children.add(child); 119 nbChildren++; 120 if (nbChildren == pageSize) { 121 reachedPageSize = true; 122 break; 123 } 124 } 125 } 126 if (!reachedPageSize) { 127 hasNextPage = childrenPageProvider.isNextPageAvailable(); 128 if (hasNextPage) { 129 childrenPageProvider.nextPage(); 130 } 131 } 132 } 133 134 return children; 135 } 136 } 137 138 @Override 139 public boolean getCanCreateChild() { 140 return canCreateChild; 141 } 142 143 @Override 144 public FolderItem createFolder(String name) { 145 try (CoreSession session = CoreInstance.openCoreSession(repositoryName, principal)) { 146 DocumentModel folder = getFileManager().createFolder(session, name, docPath); 147 if (folder == null) { 148 throw new NuxeoException( 149 String.format( 150 "Cannot create folder named '%s' as a child of doc %s. Probably because of the allowed sub-types for this doc type, please check them.", 151 name, docPath)); 152 } 153 return (FolderItem) getFileSystemItemAdapterService().getFileSystemItem(folder, this); 154 } catch (NuxeoException e) { 155 e.addInfo(String.format("Error while trying to create folder %s as a child of doc %s", name, docPath)); 156 throw e; 157 } catch (IOException e) { 158 throw new NuxeoException(String.format("Error while trying to create folder %s as a child of doc %s", name, 159 docPath), e); 160 } 161 } 162 163 @Override 164 public FileItem createFile(Blob blob) { 165 String fileName = blob.getFilename(); 166 try (CoreSession session = CoreInstance.openCoreSession(repositoryName, principal)) { 167 // TODO: manage conflict (overwrite should not necessarily be true) 168 DocumentModel file = getFileManager().createDocumentFromBlob(session, blob, docPath, true, fileName); 169 if (file == null) { 170 throw new NuxeoException( 171 String.format( 172 "Cannot create file '%s' as a child of doc %s. Probably because there are no file importers registered, please check the contributions to the <extension target=\"org.nuxeo.ecm.platform.filemanager.service.FileManagerService\" point=\"plugins\"> extension point.", 173 fileName, docPath)); 174 } 175 return (FileItem) getFileSystemItemAdapterService().getFileSystemItem(file, this); 176 } catch (NuxeoException e) { 177 e.addInfo(String.format("Error while trying to create file %s as a child of doc %s", fileName, docPath)); 178 throw e; 179 } catch (IOException e) { 180 throw new NuxeoException(String.format("Error while trying to create file %s as a child of doc %s", 181 fileName, docPath), e); 182 } 183 } 184 185 /*--------------------- Protected -----------------*/ 186 protected void initialize(DocumentModel doc) { 187 this.name = docTitle; 188 this.folder = true; 189 this.canCreateChild = doc.getCoreSession().hasPermission(doc.getRef(), SecurityConstants.ADD_CHILDREN); 190 } 191 192 protected FileManager getFileManager() { 193 return Framework.getLocalService(FileManager.class); 194 } 195 196 /*---------- Needed for JSON deserialization ----------*/ 197 protected void setCanCreateChild(boolean canCreateChild) { 198 this.canCreateChild = canCreateChild; 199 } 200 201}