001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.documentlibrary.store;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.util.CharPool;
022    import com.liferay.portal.kernel.util.FileUtil;
023    import com.liferay.portal.kernel.util.PropsKeys;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.SystemProperties;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
029    import com.liferay.portal.util.PropsUtil;
030    import com.liferay.portlet.documentlibrary.NoSuchFileException;
031    
032    import java.io.File;
033    import java.io.FileInputStream;
034    import java.io.IOException;
035    import java.io.InputStream;
036    
037    import java.util.ArrayList;
038    import java.util.Arrays;
039    import java.util.List;
040    
041    import org.jets3t.service.S3Service;
042    import org.jets3t.service.S3ServiceException;
043    import org.jets3t.service.impl.rest.httpclient.RestS3Service;
044    import org.jets3t.service.model.S3Bucket;
045    import org.jets3t.service.model.S3Object;
046    import org.jets3t.service.security.AWSCredentials;
047    
048    /**
049     * @author Brian Wing Shun Chan
050     * @author Sten Martinez
051     * @author Edward Han
052     */
053    public class S3Store extends BaseStore {
054    
055            public S3Store() {
056                    try {
057                            _s3Service = getS3Service();
058                            _s3Bucket = getS3Bucket();
059                    }
060                    catch (S3ServiceException s3se) {
061                            _log.error(s3se.getMessage());
062                    }
063            }
064    
065            @Override
066            public void addDirectory(
067                    long companyId, long repositoryId, String dirName) {
068            }
069    
070            @Override
071            public void addFile(
072                            long companyId, long repositoryId, String fileName, InputStream is)
073                    throws SystemException {
074    
075                    try {
076                            S3Object s3Object = new S3Object(
077                                    _s3Bucket,
078                                    getKey(companyId, repositoryId, fileName, VERSION_DEFAULT));
079    
080                            s3Object.setDataInputStream(is);
081    
082                            _s3Service.putObject(_s3Bucket, s3Object);
083                    }
084                    catch (S3ServiceException s3se) {
085                            throw new SystemException(s3se);
086                    }
087            }
088    
089            @Override
090            public void checkRoot(long companyId) {
091            }
092    
093            @Override
094            public void deleteDirectory(
095                            long companyId, long repositoryId, String dirName)
096                    throws SystemException {
097    
098                    try {
099                            S3Object[] s3Objects = _s3Service.listObjects(
100                                    _s3Bucket, getKey(companyId, repositoryId, dirName), null);
101    
102                            for (int i = 0; i < s3Objects.length; i++) {
103                                    S3Object s3Object = s3Objects[i];
104    
105                                    _s3Service.deleteObject(_s3Bucket, s3Object.getKey());
106                            }
107                    }
108                    catch (S3ServiceException s3se) {
109                            throw new SystemException(s3se);
110                    }
111            }
112    
113            @Override
114            public void deleteFile(long companyId, long repositoryId, String fileName)
115                    throws SystemException {
116    
117                    try {
118                            S3Object[] s3Objects = _s3Service.listObjects(
119                                    _s3Bucket, getKey(companyId, repositoryId, fileName), null);
120    
121                            for (int i = 0; i < s3Objects.length; i++) {
122                                    S3Object s3Object = s3Objects[i];
123    
124                                    _s3Service.deleteObject(_s3Bucket, s3Object.getKey());
125                            }
126                    }
127                    catch (S3ServiceException s3se) {
128                            throw new SystemException(s3se);
129                    }
130            }
131    
132            @Override
133            public void deleteFile(
134                            long companyId, long repositoryId, String fileName,
135                            String versionLabel)
136                    throws SystemException {
137    
138                    try {
139                            _s3Service.deleteObject(
140                                    _s3Bucket,
141                                    getKey(companyId, repositoryId, fileName, versionLabel));
142                    }
143                    catch (S3ServiceException s3se) {
144                            throw new SystemException(s3se);
145                    }
146            }
147    
148            @Override
149            public InputStream getFileAsStream(
150                            long companyId, long repositoryId, String fileName,
151                            String versionLabel)
152                    throws PortalException, SystemException {
153    
154                    try {
155                            if (Validator.isNull(versionLabel)) {
156                                    versionLabel = getHeadVersionLabel(
157                                            companyId, repositoryId, fileName);
158                            }
159    
160                            S3Object s3Object = _s3Service.getObject(
161                                    _s3Bucket,
162                                    getKey(companyId, repositoryId, fileName, versionLabel));
163    
164                            return s3Object.getDataInputStream();
165                    }
166                    catch (S3ServiceException s3se) {
167                            throw new SystemException(s3se);
168                    }
169            }
170    
171            public String[] getFileNames(long companyId, long repositoryId)
172                    throws SystemException {
173    
174                    List<String> fileNames = new ArrayList<String>();
175    
176                    try {
177                            S3Object[] searchObjects = _s3Service.listObjects(
178                                    _s3Bucket, getKey(companyId, repositoryId), null);
179    
180                            for (int i = 0; i < searchObjects.length; i++) {
181                                    S3Object currentObject = searchObjects[i];
182    
183                                    String fileName = getFileName(currentObject.getKey());
184    
185                                    fileNames.add(fileName);
186                            }
187                    }
188                    catch (S3ServiceException s3se) {
189                            throw new SystemException(s3se);
190                    }
191    
192                    return fileNames.toArray(new String[0]);
193            }
194    
195            @Override
196            public String[] getFileNames(
197                            long companyId, long repositoryId, String dirName)
198                    throws SystemException {
199    
200                    try {
201                            List<String> list = new ArrayList<String>();
202    
203                            S3Object[] s3Objects = _s3Service.listObjects(
204                                    _s3Bucket, getKey(companyId, repositoryId, dirName), null);
205    
206                            for (int i = 0; i < s3Objects.length; i++) {
207                                    S3Object s3Object = s3Objects[i];
208    
209                                    // Convert /${companyId}/${repositoryId}/${dirName}/${fileName}
210                                    // /${versionLabel} to /${dirName}/${fileName}
211    
212                                    String key = s3Object.getKey();
213    
214                                    int x = key.indexOf(CharPool.SLASH);
215    
216                                    x = key.indexOf(CharPool.SLASH, x + 1);
217    
218                                    int y = key.lastIndexOf(CharPool.SLASH);
219    
220                                    list.add(key.substring(x, y));
221                            }
222    
223                            return list.toArray(new String[list.size()]);
224                    }
225                    catch (S3ServiceException s3se) {
226                            throw new SystemException(s3se);
227                    }
228            }
229    
230            @Override
231            public long getFileSize(long companyId, long repositoryId, String fileName)
232                    throws PortalException, SystemException {
233    
234                    try {
235                            String versionLabel = getHeadVersionLabel(
236                                    companyId, repositoryId, fileName);
237    
238                            S3Object objectDetails = _s3Service.getObjectDetails(
239                                    _s3Bucket,
240                                    getKey(companyId, repositoryId, fileName, versionLabel));
241    
242                            return objectDetails.getContentLength();
243                    }
244                    catch (S3ServiceException s3se) {
245                            throw new SystemException(s3se);
246                    }
247            }
248    
249            @Override
250            public boolean hasDirectory(
251                    long companyId, long repositoryId, String dirName) {
252    
253                    return true;
254            }
255    
256            @Override
257            public boolean hasFile(
258                            long companyId, long repositoryId, String fileName,
259                            String versionLabel)
260                    throws SystemException {
261    
262                    try {
263                            S3Object[] s3Objects = _s3Service.listObjects(
264                                    _s3Bucket,
265                                    getKey(companyId, repositoryId, fileName, versionLabel), null);
266    
267                            if (s3Objects.length == 0) {
268                                    return false;
269                            }
270                            else {
271                                    return true;
272                            }
273                    }
274                    catch (S3ServiceException s3se) {
275                            throw new SystemException(s3se);
276                    }
277            }
278    
279            @Override
280            public void move(String srcDir, String destDir) {
281            }
282    
283            @Override
284            public void updateFile(
285                            long companyId, long repositoryId, long newRepositoryId,
286                            String fileName)
287                    throws SystemException {
288    
289                    try {
290                            S3Object[] s3Objects = _s3Service.listObjects(
291                                    _s3Bucket, getKey(companyId, repositoryId, fileName), null);
292    
293                            for (int i = 0; i < s3Objects.length; i++) {
294                                    S3Object oldS3Object = s3Objects[i];
295    
296                                    String oldKey = oldS3Object.getKey();
297    
298                                    oldS3Object = _s3Service.getObject(_s3Bucket, oldKey);
299    
300                                    File tempFile = new File(
301                                            SystemProperties.get(SystemProperties.TMP_DIR) +
302                                                    File.separator + PortalUUIDUtil.generate());
303    
304                                    FileUtil.write(tempFile, oldS3Object.getDataInputStream());
305    
306                                    InputStream is = new FileInputStream(tempFile);
307    
308                                    String newPrefix = getKey(companyId, newRepositoryId);
309    
310                                    int x = oldKey.indexOf(CharPool.SLASH);
311    
312                                    x = oldKey.indexOf(CharPool.SLASH, x + 1);
313    
314                                    String newKey =
315                                            newPrefix + oldKey.substring(x + 1, oldKey.length());
316    
317                                    S3Object newS3Object = new S3Object(_s3Bucket, newKey);
318    
319                                    newS3Object.setDataInputStream(is);
320    
321                                    _s3Service.putObject(_s3Bucket, newS3Object);
322                                    _s3Service.deleteObject(_s3Bucket, oldKey);
323    
324                                    FileUtil.delete(tempFile);
325                            }
326                    }
327                    catch (IOException ioe) {
328                            throw new SystemException(ioe);
329                    }
330                    catch (S3ServiceException s3se) {
331                            throw new SystemException(s3se);
332                    }
333            }
334    
335            public void updateFile(
336                            long companyId, long repositoryId, String fileName,
337                            String newFileName)
338                    throws SystemException {
339    
340                    try {
341                            S3Object[] s3Objects = _s3Service.listObjects(
342                                    _s3Bucket, getKey(companyId, repositoryId, fileName), null);
343    
344                            for (int i = 0; i < s3Objects.length; i++) {
345                                    S3Object oldS3Object = s3Objects[i];
346    
347                                    String oldKey = oldS3Object.getKey();
348    
349                                    oldS3Object = _s3Service.getObject(_s3Bucket, oldKey);
350    
351                                    File tempFile = new File(
352                                            SystemProperties.get(SystemProperties.TMP_DIR) +
353                                                    File.separator + PortalUUIDUtil.generate());
354    
355                                    FileUtil.write(tempFile, oldS3Object.getDataInputStream());
356    
357                                    InputStream is = new FileInputStream(tempFile);
358    
359                                    String newPrefix = getKey(companyId, repositoryId, newFileName);
360    
361                                    int x = oldKey.indexOf(StringPool.SLASH);
362    
363                                    x = oldKey.indexOf(CharPool.SLASH, x + 1);
364    
365                                    x = oldKey.indexOf(CharPool.SLASH, x + 1);
366    
367                                    String newKey =
368                                            newPrefix + oldKey.substring(x + 1, oldKey.length());
369    
370                                    S3Object newS3Object = new S3Object(_s3Bucket, newKey);
371    
372                                    newS3Object.setDataInputStream(is);
373    
374                                    _s3Service.putObject(_s3Bucket, newS3Object);
375                                    _s3Service.deleteObject(_s3Bucket, oldKey);
376    
377                                    FileUtil.delete(tempFile);
378                            }
379                    }
380                    catch (IOException ioe) {
381                            throw new SystemException(ioe);
382                    }
383                    catch (S3ServiceException s3se) {
384                            throw new SystemException(s3se);
385                    }
386            }
387    
388            @Override
389            public void updateFile(
390                            long companyId, long repositoryId, String fileName,
391                            String versionLabel, InputStream is)
392                    throws SystemException {
393    
394                    try {
395                            S3Object s3Object = new S3Object(
396                                    _s3Bucket,
397                                    getKey(companyId, repositoryId, fileName, versionLabel));
398    
399                            s3Object.setDataInputStream(is);
400    
401                            _s3Service.putObject(_s3Bucket, s3Object);
402                    }
403                    catch (S3ServiceException s3se) {
404                            throw new SystemException(s3se);
405                    }
406            }
407    
408            protected AWSCredentials getAWSCredentials() throws S3ServiceException {
409                    if (Validator.isNull(_ACCESS_KEY) || Validator.isNull(_SECRET_KEY)) {
410                            throw new S3ServiceException(
411                                    "S3 access and secret keys are not set");
412                    }
413                    else {
414                            return new AWSCredentials(_ACCESS_KEY, _SECRET_KEY);
415                    }
416            }
417    
418            protected String getFileName(String key) {
419                    int x = key.indexOf(CharPool.SLASH);
420    
421                    x = key.indexOf(CharPool.SLASH, x + 1);
422    
423                    int y = key.lastIndexOf(CharPool.SLASH);
424    
425                    return key.substring(x + 1, y);
426            }
427    
428            protected String getHeadVersionLabel(
429                            long companyId, long repositoryId, String fileName)
430                    throws PortalException, S3ServiceException {
431    
432                    S3Object[] s3Objects = _s3Service.listObjects(
433                            _s3Bucket, getKey(companyId, repositoryId, fileName), null);
434    
435                    String[] keys = new String[s3Objects.length];
436    
437                    for (int i = 0; i < s3Objects.length; i++) {
438                            S3Object s3Object = s3Objects[i];
439    
440                            keys[i] = s3Object.getKey();
441                    }
442    
443                    if (keys.length > 0) {
444                            Arrays.sort(keys);
445    
446                            String headKey = keys[keys.length - 1];
447    
448                            int x = headKey.lastIndexOf(CharPool.SLASH);
449    
450                            return headKey.substring(x + 1, headKey.length());
451                    }
452                    else {
453                            throw new NoSuchFileException(fileName);
454                    }
455            }
456    
457            protected String getKey(long companyId, long repositoryId) {
458                    StringBundler sb = new StringBundler(4);
459    
460                    sb.append(companyId);
461                    sb.append(StringPool.SLASH);
462                    sb.append(repositoryId);
463                    sb.append(StringPool.SLASH);
464    
465                    return sb.toString();
466            }
467    
468            protected String getKey(
469                    long companyId, long repositoryId, String fileName) {
470    
471                    StringBundler sb = new StringBundler(6);
472    
473                    sb.append(companyId);
474                    sb.append(StringPool.SLASH);
475                    sb.append(repositoryId);
476                    sb.append(StringPool.SLASH);
477                    sb.append(fileName);
478                    sb.append(StringPool.SLASH);
479    
480                    return sb.toString();
481            }
482    
483            protected String getKey(
484                    long companyId, long repositoryId, String fileName,
485                    String versionLabel) {
486    
487                    StringBundler sb = new StringBundler(7);
488    
489                    sb.append(companyId);
490                    sb.append(StringPool.SLASH);
491                    sb.append(repositoryId);
492                    sb.append(StringPool.SLASH);
493                    sb.append(fileName);
494                    sb.append(StringPool.SLASH);
495                    sb.append(versionLabel);
496    
497                    return sb.toString();
498            }
499    
500            protected S3Bucket getS3Bucket() throws S3ServiceException {
501                    if (Validator.isNull(_BUCKET_NAME)) {
502                            throw new S3ServiceException("S3 bucket name is not set");
503                    }
504                    else {
505                            return getS3Service().createBucket(_BUCKET_NAME);
506                    }
507            }
508    
509            protected S3Service getS3Service() throws S3ServiceException {
510                    AWSCredentials credentials = getAWSCredentials();
511    
512                    return new RestS3Service(credentials);
513            }
514    
515            private static final String _ACCESS_KEY = PropsUtil.get(
516                    PropsKeys.DL_STORE_S3_ACCESS_KEY);
517    
518            private static final String _BUCKET_NAME = PropsUtil.get(
519                    PropsKeys.DL_STORE_S3_BUCKET_NAME);
520    
521            private static final String _SECRET_KEY = PropsUtil.get(
522                    PropsKeys.DL_STORE_S3_SECRET_KEY);
523    
524            private static Log _log = LogFactoryUtil.getLog(S3Store.class);
525    
526            private S3Bucket _s3Bucket;
527            private S3Service _s3Service;
528    
529    }