1 package org.exoplatform.commons.file.services.impl;
2
3 import org.apache.commons.lang.StringUtils;
4 import org.exoplatform.commons.api.persistence.ExoTransactional;
5 import org.exoplatform.commons.file.model.NameSpace;
6 import org.exoplatform.commons.file.resource.BinaryProvider;
7 import org.exoplatform.commons.file.model.FileItem;
8 import org.exoplatform.commons.file.model.FileInfo;
9 import org.exoplatform.commons.file.services.FileService;
10 import org.exoplatform.commons.file.services.FileStorageException;
11 import org.exoplatform.commons.file.services.NameSpaceService;
12 import org.exoplatform.commons.file.storage.DataStorage;
13 import org.exoplatform.services.log.ExoLogger;
14 import org.exoplatform.services.log.Log;
15
16 import java.io.IOException;
17 import java.io.InputStream;
18
19
20
21
22
23
24 public class FileServiceImpl implements FileService {
25
26 private static final Log LOG = ExoLogger.getLogger(FileServiceImpl.class);
27
28 private DataStorage dataStorage;
29
30 private BinaryProvider binaryProvider;
31
32 private NameSpaceService nameSpaceService;
33
34 public FileServiceImpl(DataStorage dataStorage, BinaryProvider resourceProvider, NameSpaceService nameSpaceService) throws Exception {
35 this.dataStorage = dataStorage;
36 this.binaryProvider = resourceProvider;
37 this.nameSpaceService = nameSpaceService;
38 }
39
40 @Override
41 public FileInfo getFileInfo(long id){
42 return dataStorage.getFileInfo(id);
43 }
44
45 @Override
46 public FileItem getFile(long id) throws FileStorageException {
47 FileItem fileItem;
48 FileInfo fileInfo = getFileInfo(id);
49
50 if (fileInfo == null || StringUtils.isEmpty(fileInfo.getChecksum())) {
51 return null;
52 }
53 try {
54 fileItem = new FileItem(fileInfo, null);
55 InputStream inputStream = binaryProvider.getStream(fileInfo.getChecksum());
56 fileItem.setInputStream(inputStream);
57 } catch (Exception e) {
58 throw new FileStorageException("Cannot get File Item ID=" + id, e);
59 }
60
61 return fileItem;
62 }
63
64 @Override
65 @ExoTransactional
66 public FileItem writeFile(FileItem file) throws FileStorageException, IOException {
67 if (file.getFileInfo() == null || StringUtils.isEmpty(file.getFileInfo().getChecksum())) {
68 throw new IllegalArgumentException("Checksum is required to persist the binary");
69 }
70 FileInfo fileInfo = file.getFileInfo();
71 NameSpace nSpace;
72 if (fileInfo.getNameSpace() != null && !fileInfo.getNameSpace().isEmpty()) {
73 nSpace = dataStorage.getNameSpace(fileInfo.getNameSpace());
74 } else {
75 nSpace = dataStorage.getNameSpace(nameSpaceService.getDefaultNameSpace());
76 }
77 FileStorageTransaction transaction = new FileStorageTransaction(fileInfo, nSpace);
78 FileInfo createdFileInfoEntity = transaction.twoPhaseCommit(2, file.getAsStream());
79 if (createdFileInfoEntity != null) {
80 fileInfo.setId(createdFileInfoEntity.getId());
81 file.setFileInfo(fileInfo);
82 return file;
83 }
84 return null;
85 }
86
87 @Override
88 @ExoTransactional
89 public FileItem updateFile(FileItem file) throws FileStorageException, IOException {
90 if (file.getFileInfo() == null || StringUtils.isEmpty(file.getFileInfo().getChecksum())) {
91 throw new IllegalArgumentException("Checksum is required to persist the binary");
92 }
93 FileInfo fileInfo = file.getFileInfo();
94 NameSpace nSpace;
95 if (fileInfo.getNameSpace() != null && !fileInfo.getNameSpace().isEmpty()) {
96 nSpace = dataStorage.getNameSpace(fileInfo.getNameSpace());
97 } else {
98 nSpace = dataStorage.getNameSpace(nameSpaceService.getDefaultNameSpace());
99 }
100 FileStorageTransaction transaction = new FileStorageTransaction(fileInfo, nSpace);
101 FileInfo createdFileInfoEntity = transaction.twoPhaseCommit(0, file.getAsStream());
102 if (createdFileInfoEntity != null) {
103 fileInfo.setId(createdFileInfoEntity.getId());
104 file.setFileInfo(fileInfo);
105 return file;
106 }
107 return null;
108 }
109
110 @Override
111 public FileInfo deleteFile(long id) {
112 FileInfo fileInfo = dataStorage.getFileInfo(id);
113 if (fileInfo != null) {
114 fileInfo.setDeleted(true);
115 }
116 return dataStorage.updateFileInfo(fileInfo);
117 }
118
119
120 private class FileStorageTransaction {
121
122
123
124 final int UPDATE = 0;
125
126
127
128
129 final int REMOVE = 1;
130
131
132
133
134 final int INSERT = 2;
135
136 private FileInfo fileInfo;
137
138 private NameSpace nameSpace;
139
140 public FileStorageTransaction(FileInfo fileInfo, NameSpace nameSpace) {
141 this.fileInfo = fileInfo;
142 this.nameSpace = nameSpace;
143 }
144
145 public FileInfo twoPhaseCommit(int operation, InputStream inputStream) throws FileStorageException {
146 FileInfo createdFileInfoEntity = null;
147 if (operation == INSERT) {
148 boolean created = false;
149 try {
150 if (!binaryProvider.exists(fileInfo.getChecksum())) {
151 binaryProvider.put(fileInfo.getChecksum(), inputStream);
152 created = true;
153 }
154 if (binaryProvider.exists(fileInfo.getChecksum())) {
155 createdFileInfoEntity = dataStorage.create(fileInfo, nameSpace);
156 return createdFileInfoEntity;
157 } else {
158 throw new FileStorageException("Error while writing file " + fileInfo.getName());
159 }
160 } catch (Exception e) {
161 try {
162 if (created) {
163 binaryProvider.remove(fileInfo.getChecksum());
164 }
165 } catch (IOException e1) {
166 LOG.error("Error while rollback writing file");
167 }
168 throw new FileStorageException("Error while writing file " + fileInfo.getName(), e);
169 }
170
171 } else if (operation == REMOVE) {
172 fileInfo.setDeleted(true);
173 dataStorage.updateFileInfo(fileInfo);
174 } else if (operation == UPDATE) {
175 try {
176 boolean updated = false;
177 FileInfo oldFile = dataStorage.getFileInfo(fileInfo.getId());
178 if (oldFile == null || oldFile.getChecksum().isEmpty()
179 || !oldFile.getChecksum().equals(fileInfo.getChecksum())) {
180 if (!binaryProvider.exists(fileInfo.getChecksum())) {
181 binaryProvider.put(fileInfo.getChecksum(), inputStream);
182 }
183 updated = true;
184 }
185 if (updated && dataStorage.sharedChecksum(oldFile.getChecksum()) ==1) {
186 dataStorage.createOrphanFile(oldFile);
187 }
188 if (binaryProvider.exists(fileInfo.getChecksum())) {
189 createdFileInfoEntity = dataStorage.updateFileInfo(fileInfo);
190 return createdFileInfoEntity;
191 } else {
192 throw new FileStorageException("Error while writing file " + fileInfo.getName());
193 }
194 } catch (Exception e) {
195 try {
196 binaryProvider.remove(fileInfo.getChecksum());
197 } catch (IOException e1) {
198 LOG.error("Error while rollback writing file");
199 }
200 throw new FileStorageException("Error while writing file " + fileInfo.getName(), e);
201 }
202 }
203 return null;
204 }
205 }
206
207 }