001/* 002 * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Antoine Taillefer <ataillefer@nuxeo.com> 018 */ 019package org.nuxeo.drive.adapter.impl; 020 021import static org.nuxeo.ecm.platform.query.nxql.CoreQueryDocumentPageProvider.CORE_SESSION_PROPERTY; 022 023import java.io.IOException; 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029 030import org.nuxeo.drive.adapter.FileItem; 031import org.nuxeo.drive.adapter.FileSystemItem; 032import org.nuxeo.drive.adapter.FolderItem; 033import org.nuxeo.ecm.core.api.Blob; 034import org.nuxeo.ecm.core.api.CoreInstance; 035import org.nuxeo.ecm.core.api.CoreSession; 036import org.nuxeo.ecm.core.api.DocumentModel; 037import org.nuxeo.ecm.core.api.NuxeoException; 038import org.nuxeo.ecm.core.api.security.SecurityConstants; 039import org.nuxeo.ecm.core.schema.FacetNames; 040import org.nuxeo.ecm.platform.filemanager.api.FileManager; 041import org.nuxeo.ecm.platform.query.api.PageProvider; 042import org.nuxeo.ecm.platform.query.api.PageProviderService; 043import org.nuxeo.runtime.api.Framework; 044 045/** 046 * {@link DocumentModel} backed implementation of a {@link FolderItem}. 047 * 048 * @author Antoine Taillefer 049 */ 050public class DocumentBackedFolderItem extends AbstractDocumentBackedFileSystemItem implements FolderItem { 051 052 private static final long serialVersionUID = 1L; 053 054 private static final String FOLDER_ITEM_CHILDREN_PAGE_PROVIDER = "FOLDER_ITEM_CHILDREN"; 055 056 protected boolean canCreateChild; 057 058 public DocumentBackedFolderItem(String factoryName, DocumentModel doc) { 059 this(factoryName, doc, false); 060 } 061 062 public DocumentBackedFolderItem(String factoryName, DocumentModel doc, boolean relaxSyncRootConstraint) { 063 super(factoryName, doc, relaxSyncRootConstraint); 064 initialize(doc); 065 } 066 067 public DocumentBackedFolderItem(String factoryName, FolderItem parentItem, DocumentModel doc) { 068 this(factoryName, parentItem, doc, false); 069 } 070 071 public DocumentBackedFolderItem(String factoryName, FolderItem parentItem, DocumentModel doc, 072 boolean relaxSyncRootConstraint) { 073 super(factoryName, parentItem, doc, relaxSyncRootConstraint); 074 initialize(doc); 075 } 076 077 protected DocumentBackedFolderItem() { 078 // Needed for JSON deserialization 079 } 080 081 /*--------------------- FileSystemItem ---------------------*/ 082 @Override 083 public void rename(String name) { 084 try (CoreSession session = CoreInstance.openCoreSession(repositoryName, principal)) { 085 // Update doc properties 086 DocumentModel doc = getDocument(session); 087 doc.setPropertyValue("dc:title", name); 088 doc = session.saveDocument(doc); 089 session.save(); 090 // Update FileSystemItem attributes 091 this.docTitle = name; 092 this.name = name; 093 updateLastModificationDate(doc); 094 } 095 } 096 097 /*--------------------- FolderItem -----------------*/ 098 @Override 099 @SuppressWarnings("unchecked") 100 public List<FileSystemItem> getChildren() { 101 try (CoreSession session = CoreInstance.openCoreSession(repositoryName, principal)) { 102 PageProviderService pageProviderService = Framework.getLocalService(PageProviderService.class); 103 Map<String, Serializable> props = new HashMap<String, Serializable>(); 104 props.put(CORE_SESSION_PROPERTY, (Serializable) session); 105 PageProvider<DocumentModel> childrenPageProvider = (PageProvider<DocumentModel>) pageProviderService.getPageProvider( 106 FOLDER_ITEM_CHILDREN_PAGE_PROVIDER, null, null, 0L, props, docId); 107 Long pageSize = childrenPageProvider.getPageSize(); 108 109 List<FileSystemItem> children = new ArrayList<FileSystemItem>(); 110 int nbChildren = 0; 111 boolean reachedPageSize = false; 112 boolean hasNextPage = true; 113 // Since query results are filtered, make sure we iterate on PageProvider to get at most its page size 114 // number of 115 // FileSystemItems 116 while (nbChildren < pageSize && hasNextPage) { 117 List<DocumentModel> dmChildren = childrenPageProvider.getCurrentPage(); 118 for (DocumentModel dmChild : dmChildren) { 119 FileSystemItem child = getFileSystemItemAdapterService().getFileSystemItem(dmChild, this); 120 if (child != null) { 121 children.add(child); 122 nbChildren++; 123 if (nbChildren == pageSize) { 124 reachedPageSize = true; 125 break; 126 } 127 } 128 } 129 if (!reachedPageSize) { 130 hasNextPage = childrenPageProvider.isNextPageAvailable(); 131 if (hasNextPage) { 132 childrenPageProvider.nextPage(); 133 } 134 } 135 } 136 137 return children; 138 } 139 } 140 141 @Override 142 public boolean getCanCreateChild() { 143 return canCreateChild; 144 } 145 146 @Override 147 public FolderItem createFolder(String name) { 148 try (CoreSession session = CoreInstance.openCoreSession(repositoryName, principal)) { 149 DocumentModel folder = getFileManager().createFolder(session, name, docPath); 150 if (folder == null) { 151 throw new NuxeoException( 152 String.format( 153 "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.", 154 name, docPath)); 155 } 156 return (FolderItem) getFileSystemItemAdapterService().getFileSystemItem(folder, this); 157 } catch (NuxeoException e) { 158 e.addInfo(String.format("Error while trying to create folder %s as a child of doc %s", name, docPath)); 159 throw e; 160 } catch (IOException e) { 161 throw new NuxeoException(String.format("Error while trying to create folder %s as a child of doc %s", name, 162 docPath), e); 163 } 164 } 165 166 @Override 167 public FileItem createFile(Blob blob) { 168 String fileName = blob.getFilename(); 169 try (CoreSession session = CoreInstance.openCoreSession(repositoryName, principal)) { 170 // TODO: manage conflict (overwrite should not necessarily be true) 171 DocumentModel file = getFileManager().createDocumentFromBlob(session, blob, docPath, true, fileName); 172 if (file == null) { 173 throw new NuxeoException( 174 String.format( 175 "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.", 176 fileName, docPath)); 177 } 178 return (FileItem) getFileSystemItemAdapterService().getFileSystemItem(file, this); 179 } catch (NuxeoException e) { 180 e.addInfo(String.format("Error while trying to create file %s as a child of doc %s", fileName, docPath)); 181 throw e; 182 } catch (IOException e) { 183 throw new NuxeoException(String.format("Error while trying to create file %s as a child of doc %s", 184 fileName, docPath), e); 185 } 186 } 187 188 /*--------------------- Protected -----------------*/ 189 protected void initialize(DocumentModel doc) { 190 this.name = docTitle; 191 this.folder = true; 192 this.canCreateChild = !doc.hasFacet(FacetNames.PUBLISH_SPACE) 193 && doc.getCoreSession().hasPermission(doc.getRef(), SecurityConstants.ADD_CHILDREN); 194 } 195 196 protected FileManager getFileManager() { 197 return Framework.getLocalService(FileManager.class); 198 } 199 200 /*---------- Needed for JSON deserialization ----------*/ 201 protected void setCanCreateChild(boolean canCreateChild) { 202 this.canCreateChild = canCreateChild; 203 } 204 205}