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