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.service.impl; 020 021import java.io.Serializable; 022import java.security.Principal; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026 027import javax.naming.NamingException; 028import javax.transaction.RollbackException; 029import javax.transaction.Status; 030import javax.transaction.Synchronization; 031import javax.transaction.SystemException; 032import javax.transaction.Transaction; 033 034import org.apache.commons.logging.Log; 035import org.apache.commons.logging.LogFactory; 036import org.nuxeo.drive.adapter.FileItem; 037import org.nuxeo.drive.adapter.FileSystemItem; 038import org.nuxeo.drive.adapter.FolderItem; 039import org.nuxeo.drive.adapter.RootlessItemException; 040import org.nuxeo.drive.adapter.ScrollFileSystemItemList; 041import org.nuxeo.drive.service.FileSystemItemAdapterService; 042import org.nuxeo.drive.service.FileSystemItemManager; 043import org.nuxeo.ecm.core.api.Blob; 044import org.nuxeo.ecm.core.api.CloseableCoreSession; 045import org.nuxeo.ecm.core.api.CoreInstance; 046import org.nuxeo.ecm.core.api.CoreSession; 047import org.nuxeo.ecm.core.api.NuxeoException; 048import org.nuxeo.runtime.api.Framework; 049import org.nuxeo.runtime.transaction.TransactionHelper; 050 051/** 052 * Default implementation of the {@link FileSystemItemManager}. 053 * 054 * @author Antoine Taillefer 055 */ 056public class FileSystemItemManagerImpl implements FileSystemItemManager { 057 058 private static final Log log = LogFactory.getLog(FileSystemItemManagerImpl.class); 059 060 /*------------- Opened sessions against each repository ----------------*/ 061 protected final ThreadLocal<Map<String, CloseableCoreSession>> openedSessions = new ThreadLocal<Map<String, CloseableCoreSession>>() { 062 @Override 063 protected Map<String, CloseableCoreSession> initialValue() { 064 return new HashMap<>(); 065 } 066 }; 067 068 @Deprecated 069 @Override 070 public CoreSession getSession(String repositoryName, Principal principal) { 071 final String sessionKey = repositoryName + "/" + principal.getName(); 072 CoreSession session = openedSessions.get().get(sessionKey); 073 if (session == null) { 074 Map<String, Serializable> context = new HashMap<String, Serializable>(); 075 context.put("principal", (Serializable) principal); 076 final CloseableCoreSession newSession = CoreInstance.openCoreSession(repositoryName, principal); 077 openedSessions.get().put(sessionKey, newSession); 078 try { 079 Transaction t = TransactionHelper.lookupTransactionManager().getTransaction(); 080 if (t == null) { 081 throw new RuntimeException("FileSystemItemManagerImpl requires an active transaction."); 082 } 083 t.registerSynchronization(new SessionCloser(newSession, sessionKey)); 084 } catch (SystemException | NamingException | RollbackException e) { 085 throw new NuxeoException(e); 086 } 087 session = newSession; 088 } 089 return session; 090 } 091 092 /** 093 * Closer for a {@link CoreSession} object held by {@link #openedSessions}. It is synchronized with the transaction 094 * within which the {@link CoreSession} was opened. 095 */ 096 protected class SessionCloser implements Synchronization { 097 098 protected final CloseableCoreSession session; 099 100 protected final String sessionKey; 101 102 protected SessionCloser(CloseableCoreSession session, String sessionKey) { 103 this.session = session; 104 this.sessionKey = sessionKey; 105 } 106 107 @Override 108 public void beforeCompletion() { 109 session.close(); 110 } 111 112 @Override 113 public void afterCompletion(int status) { 114 openedSessions.get().remove(sessionKey); 115 if (status != Status.STATUS_COMMITTED) { 116 session.close(); 117 } 118 } 119 } 120 121 /*------------- Read operations ----------------*/ 122 @Override 123 public List<FileSystemItem> getTopLevelChildren(Principal principal) { 124 return getTopLevelFolder(principal).getChildren(); 125 } 126 127 @Override 128 public FolderItem getTopLevelFolder(Principal principal) { 129 return getFileSystemItemAdapterService().getTopLevelFolderItemFactory().getTopLevelFolderItem(principal); 130 } 131 132 @Override 133 public boolean exists(String id, Principal principal) { 134 return getFileSystemItemAdapterService().getFileSystemItemFactoryForId(id).exists(id, principal); 135 } 136 137 @Override 138 public FileSystemItem getFileSystemItemById(String id, Principal principal) { 139 try { 140 return getFileSystemItemAdapterService().getFileSystemItemFactoryForId(id).getFileSystemItemById(id, 141 principal); 142 } catch (RootlessItemException e) { 143 if (log.isDebugEnabled()) { 144 log.debug(String.format( 145 "RootlessItemException thrown while trying to get file system item with id %s, returning null.", 146 id)); 147 } 148 return null; 149 } 150 } 151 152 @Override 153 public FileSystemItem getFileSystemItemById(String id, String parentId, Principal principal) { 154 try { 155 return getFileSystemItemAdapterService().getFileSystemItemFactoryForId(id).getFileSystemItemById(id, 156 parentId, principal); 157 } catch (RootlessItemException e) { 158 if (log.isDebugEnabled()) { 159 log.debug(String.format( 160 "RootlessItemException thrown while trying to get file system item with id %s and parent id %s, returning null.", 161 id, parentId)); 162 } 163 return null; 164 } 165 } 166 167 @Override 168 public List<FileSystemItem> getChildren(String id, Principal principal) { 169 FileSystemItem fileSystemItem = getFileSystemItemById(id, principal); 170 if (fileSystemItem == null) { 171 throw new NuxeoException(String.format( 172 "Cannot get the children of file system item with id %s because it doesn't exist.", id)); 173 } 174 if (!(fileSystemItem instanceof FolderItem)) { 175 throw new NuxeoException(String.format( 176 "Cannot get the children of file system item with id %s because it is not a folder.", id)); 177 } 178 FolderItem folderItem = (FolderItem) fileSystemItem; 179 return folderItem.getChildren(); 180 } 181 182 @Override 183 public ScrollFileSystemItemList scrollDescendants(String id, Principal principal, String scrollId, int batchSize, 184 long keepAlive) { 185 FileSystemItem fileSystemItem = getFileSystemItemById(id, principal); 186 if (fileSystemItem == null) { 187 throw new NuxeoException(String.format( 188 "Cannot get the descendants of file system item with id %s because it doesn't exist.", id)); 189 } 190 if (!(fileSystemItem instanceof FolderItem)) { 191 throw new NuxeoException(String.format( 192 "Cannot get the descendants of file system item with id %s because it is not a folder.", id)); 193 } 194 FolderItem folderItem = (FolderItem) fileSystemItem; 195 return folderItem.scrollDescendants(scrollId, batchSize, keepAlive); 196 } 197 198 @Override 199 public boolean canMove(String srcId, String destId, Principal principal) { 200 FileSystemItem srcFsItem = getFileSystemItemById(srcId, principal); 201 if (srcFsItem == null) { 202 return false; 203 } 204 FileSystemItem destFsItem = getFileSystemItemById(destId, principal); 205 if (!(destFsItem instanceof FolderItem)) { 206 return false; 207 } 208 return srcFsItem.canMove((FolderItem) destFsItem); 209 } 210 211 /*------------- Write operations ---------------*/ 212 @Override 213 public FolderItem createFolder(String parentId, String name, Principal principal, boolean overwrite) { 214 FileSystemItem parentFsItem = getFileSystemItemById(parentId, principal); 215 if (parentFsItem == null) { 216 throw new NuxeoException(String.format( 217 "Cannot create a folder in file system item with id %s because it doesn't exist.", parentId)); 218 } 219 if (!(parentFsItem instanceof FolderItem)) { 220 throw new NuxeoException(String.format( 221 "Cannot create a folder in file system item with id %s because it is not a folder but is: %s", 222 parentId, parentFsItem)); 223 } 224 FolderItem parentFolder = (FolderItem) parentFsItem; 225 return parentFolder.createFolder(name, overwrite); 226 } 227 228 @Override 229 public FileItem createFile(String parentId, Blob blob, Principal principal, boolean overwrite) { 230 FileSystemItem parentFsItem = getFileSystemItemById(parentId, principal); 231 if (parentFsItem == null) { 232 throw new NuxeoException(String.format( 233 "Cannot create a file in file system item with id %s because it doesn't exist.", parentId)); 234 } 235 if (!(parentFsItem instanceof FolderItem)) { 236 throw new NuxeoException(String.format( 237 "Cannot create a file in file system item with id %s because it is not a folder but is: %s", 238 parentId, parentFsItem)); 239 } 240 FolderItem parentFolder = (FolderItem) parentFsItem; 241 return parentFolder.createFile(blob, overwrite); 242 } 243 244 @Override 245 public FileItem updateFile(String id, Blob blob, Principal principal) { 246 FileSystemItem fsItem = getFileSystemItemById(id, principal); 247 return updateFile(fsItem, blob); 248 } 249 250 @Override 251 public FileItem updateFile(String id, String parentId, Blob blob, Principal principal) { 252 FileSystemItem fsItem = getFileSystemItemById(id, parentId, principal); 253 return updateFile(fsItem, blob); 254 } 255 256 @Override 257 public void delete(String id, Principal principal) { 258 FileSystemItem fsItem = getFileSystemItemById(id, principal); 259 delete(fsItem); 260 } 261 262 @Override 263 public void delete(String id, String parentId, Principal principal) { 264 FileSystemItem fsItem = getFileSystemItemById(id, parentId, principal); 265 delete(fsItem); 266 } 267 268 @Override 269 public FileSystemItem rename(String id, String name, Principal principal) { 270 FileSystemItem fsItem = getFileSystemItemById(id, principal); 271 if (fsItem == null) { 272 throw new NuxeoException( 273 String.format("Cannot rename file system item with id %s because it doesn't exist.", id)); 274 } 275 fsItem.rename(name); 276 return fsItem; 277 } 278 279 @Override 280 public FileSystemItem move(String srcId, String destId, Principal principal) { 281 FileSystemItem srcFsItem = getFileSystemItemById(srcId, principal); 282 if (srcFsItem == null) { 283 throw new NuxeoException( 284 String.format("Cannot move file system item with id %s because it doesn't exist.", srcId)); 285 } 286 FileSystemItem destFsItem = getFileSystemItemById(destId, principal); 287 if (destFsItem == null) { 288 throw new NuxeoException(String.format( 289 "Cannot move a file system item to file system item with id %s because it doesn't exist.", destId)); 290 } 291 if (!(destFsItem instanceof FolderItem)) { 292 throw new NuxeoException(String.format( 293 "Cannot move a file system item to file system item with id %s because it is not a folder.", 294 destId)); 295 } 296 return srcFsItem.move((FolderItem) destFsItem); 297 } 298 299 /*------------- Protected ---------------*/ 300 protected FileSystemItemAdapterService getFileSystemItemAdapterService() { 301 return Framework.getService(FileSystemItemAdapterService.class); 302 } 303 304 protected FileItem updateFile(FileSystemItem fsItem, Blob blob) { 305 if (fsItem == null) { 306 throw new NuxeoException("Cannot update the content of file system item because it doesn't exist."); 307 } 308 if (!(fsItem instanceof FileItem)) { 309 throw new NuxeoException( 310 String.format("Cannot update the content of file system item with id %s because it is not a file.", 311 fsItem.getId())); 312 } 313 FileItem file = (FileItem) fsItem; 314 file.setBlob(blob); 315 return file; 316 } 317 318 protected void delete(FileSystemItem fsItem) { 319 if (fsItem == null) { 320 throw new NuxeoException("Cannot delete file system item because it doesn't exist."); 321 } 322 fsItem.delete(); 323 } 324 325}