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