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