001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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(
115                            long companyId, long repositoryId, String fileName)
116                    throws SystemException {
117    
118                    try {
119                            S3Object[] s3Objects = _s3Service.listObjects(
120                                    _s3Bucket, getKey(companyId, repositoryId, fileName), null);
121    
122                            for (int i = 0; i < s3Objects.length; i++) {
123                                    S3Object s3Object = s3Objects[i];
124    
125                                    _s3Service.deleteObject(_s3Bucket, s3Object.getKey());
126                            }
127                    }
128                    catch (S3ServiceException s3se) {
129                            throw new SystemException(s3se);
130                    }
131            }
132    
133            @Override
134            public void deleteFile(
135                            long companyId, long repositoryId, String fileName,
136                            String versionLabel)
137                    throws SystemException {
138    
139                    try {
140                            _s3Service.deleteObject(
141                                    _s3Bucket,
142                                    getKey(companyId, repositoryId, fileName, versionLabel));
143                    }
144                    catch (S3ServiceException s3se) {
145                            throw new SystemException(s3se);
146                    }
147            }
148    
149            @Override
150            public InputStream getFileAsStream(
151                            long companyId, long repositoryId, String fileName,
152                            String versionLabel)
153                    throws PortalException, SystemException {
154    
155                    try {
156                            if (Validator.isNull(versionLabel)) {
157                                    versionLabel = getHeadVersionLabel(
158                                            companyId, repositoryId, fileName);
159                            }
160    
161                            S3Object s3Object = _s3Service.getObject(
162                                    _s3Bucket,
163                                    getKey(companyId, repositoryId, fileName, versionLabel));
164    
165                            return s3Object.getDataInputStream();
166                    }
167                    catch (S3ServiceException s3se) {
168                            throw new SystemException(s3se);
169                    }
170            }
171    
172            public String[] getFileNames(long companyId, long repositoryId)
173                    throws SystemException {
174    
175                    List<String> fileNames = new ArrayList<String>();
176    
177                    try {
178                            S3Object[] searchObjects = _s3Service.listObjects(
179                                    _s3Bucket, getKey(companyId, repositoryId), null);
180    
181                            for (int i = 0; i < searchObjects.length; i++) {
182                                    S3Object currentObject = searchObjects[i];
183    
184                                    String fileName = getFileName(currentObject.getKey());
185    
186                                    fileNames.add(fileName);
187                            }
188                    }
189                    catch (S3ServiceException s3se) {
190                            throw new SystemException(s3se);
191                    }
192    
193                    return fileNames.toArray(new String[0]);
194            }
195    
196            @Override
197            public String[] getFileNames(
198                            long companyId, long repositoryId, String dirName)
199                    throws SystemException {
200    
201                    try {
202                            List<String> list = new ArrayList<String>();
203    
204                            S3Object[] s3Objects = _s3Service.listObjects(
205                                    _s3Bucket, getKey(companyId, repositoryId, dirName), null);
206    
207                            for (int i = 0; i < s3Objects.length; i++) {
208                                    S3Object s3Object = s3Objects[i];
209    
210                                    // Convert /${companyId}/${repositoryId}/${dirName}/${fileName}
211                                    // /${versionLabel} to /${dirName}/${fileName}
212    
213                                    String key = s3Object.getKey();
214    
215                                    int x = key.indexOf(CharPool.SLASH);
216    
217                                    x = key.indexOf(CharPool.SLASH, x + 1);
218    
219                                    int y = key.lastIndexOf(CharPool.SLASH);
220    
221                                    list.add(key.substring(x, y));
222                            }
223    
224                            return list.toArray(new String[list.size()]);
225                    }
226                    catch (S3ServiceException s3se) {
227                            throw new SystemException(s3se);
228                    }
229            }
230    
231            @Override
232            public long getFileSize(
233                            long companyId, long repositoryId, String fileName)
234                    throws PortalException, SystemException {
235    
236                    try {
237                            String versionLabel = getHeadVersionLabel(
238                                    companyId, repositoryId, fileName);
239    
240                            S3Object objectDetails = _s3Service.getObjectDetails(
241                                    _s3Bucket,
242                                    getKey(companyId, repositoryId, fileName, versionLabel));
243    
244                            return objectDetails.getContentLength();
245                    }
246                    catch (S3ServiceException s3se) {
247                            throw new SystemException(s3se);
248                    }
249            }
250    
251            @Override
252            public boolean hasDirectory(
253                    long companyId, long repositoryId, String dirName) {
254    
255                    return true;
256            }
257    
258            @Override
259            public boolean hasFile(
260                            long companyId, long repositoryId, String fileName,
261                            String versionLabel)
262                    throws SystemException {
263    
264                    try {
265                            S3Object[] s3Objects = _s3Service.listObjects(
266                                    _s3Bucket,
267                                    getKey(companyId, repositoryId, fileName, versionLabel), null);
268    
269                            if (s3Objects.length == 0) {
270                                    return false;
271                            }
272                            else {
273                                    return true;
274                            }
275                    }
276                    catch (S3ServiceException s3se) {
277                            throw new SystemException(s3se);
278                    }
279            }
280    
281            @Override
282            public void move(String srcDir, String destDir) {
283            }
284    
285            @Override
286            public void updateFile(
287                            long companyId, long repositoryId, long newRepositoryId,
288                            String fileName)
289                    throws SystemException {
290    
291                    try {
292                            S3Object[] s3Objects = _s3Service.listObjects(
293                                    _s3Bucket, getKey(companyId, repositoryId, fileName), null);
294    
295                            for (int i = 0; i < s3Objects.length; i++) {
296                                    S3Object oldS3Object = s3Objects[i];
297    
298                                    String oldKey = oldS3Object.getKey();
299    
300                                    oldS3Object = _s3Service.getObject(_s3Bucket, oldKey);
301    
302                                    File tempFile = new File(
303                                            SystemProperties.get(SystemProperties.TMP_DIR) +
304                                                    File.separator + PortalUUIDUtil.generate());
305    
306                                    FileUtil.write(tempFile, oldS3Object.getDataInputStream());
307    
308                                    InputStream is = new FileInputStream(tempFile);
309    
310                                    String newPrefix = getKey(companyId, newRepositoryId);
311    
312                                    int x = oldKey.indexOf(CharPool.SLASH);
313    
314                                    x = oldKey.indexOf(CharPool.SLASH, x + 1);
315    
316                                    String newKey =
317                                            newPrefix + oldKey.substring(x + 1, oldKey.length());
318    
319                                    S3Object newS3Object = new S3Object(
320                                            _s3Bucket, newKey);
321    
322                                    newS3Object.setDataInputStream(is);
323    
324                                    _s3Service.putObject(_s3Bucket, newS3Object);
325                                    _s3Service.deleteObject(_s3Bucket, oldKey);
326    
327                                    FileUtil.delete(tempFile);
328                            }
329                    }
330                    catch (IOException ioe) {
331                            throw new SystemException(ioe);
332                    }
333                    catch (S3ServiceException s3se) {
334                            throw new SystemException(s3se);
335                    }
336            }
337    
338            public void updateFile(
339                            long companyId, long repositoryId, String fileName,
340                            String newFileName)
341                    throws SystemException {
342    
343                    try {
344                            S3Object[] s3Objects = _s3Service.listObjects(
345                                    _s3Bucket, getKey(companyId, repositoryId, fileName), null);
346    
347                            for (int i = 0; i < s3Objects.length; i++) {
348                                    S3Object oldS3Object = s3Objects[i];
349    
350                                    String oldKey = oldS3Object.getKey();
351    
352                                    oldS3Object = _s3Service.getObject(_s3Bucket, oldKey);
353    
354                                    File tempFile = new File(
355                                            SystemProperties.get(SystemProperties.TMP_DIR) +
356                                                    File.separator + PortalUUIDUtil.generate());
357    
358                                    FileUtil.write(tempFile, oldS3Object.getDataInputStream());
359    
360                                    InputStream is = new FileInputStream(tempFile);
361    
362                                    String newPrefix = getKey(companyId, repositoryId, newFileName);
363    
364                                    int x = oldKey.indexOf(StringPool.SLASH);
365    
366                                    x = oldKey.indexOf(CharPool.SLASH, x + 1);
367    
368                                    x = oldKey.indexOf(CharPool.SLASH, x + 1);
369    
370                                    String newKey =
371                                            newPrefix + oldKey.substring(x + 1, oldKey.length());
372    
373                                    S3Object newS3Object = new S3Object(
374                                            _s3Bucket, newKey);
375    
376                                    newS3Object.setDataInputStream(is);
377    
378                                    _s3Service.putObject(_s3Bucket, newS3Object);
379                                    _s3Service.deleteObject(_s3Bucket, oldKey);
380    
381                                    FileUtil.delete(tempFile);
382                            }
383                    }
384                    catch (IOException ioe) {
385                            throw new SystemException(ioe);
386                    }
387                    catch (S3ServiceException s3se) {
388                            throw new SystemException(s3se);
389                    }
390            }
391    
392            @Override
393            public void updateFile(
394                            long companyId, long repositoryId, String fileName,
395                            String versionLabel, InputStream is)
396                    throws SystemException {
397    
398                    try {
399                            S3Object s3Object = new S3Object(
400                                    _s3Bucket,
401                                    getKey(companyId, repositoryId, fileName, versionLabel));
402    
403                            s3Object.setDataInputStream(is);
404    
405                            _s3Service.putObject(_s3Bucket, s3Object);
406                    }
407                    catch (S3ServiceException s3se) {
408                            throw new SystemException(s3se);
409                    }
410            }
411    
412            protected AWSCredentials getAWSCredentials() throws S3ServiceException {
413                    if (Validator.isNull(_ACCESS_KEY) || Validator.isNull(_SECRET_KEY)) {
414                            throw new S3ServiceException(
415                                    "S3 access and secret keys are not set");
416                    }
417                    else {
418                            return new AWSCredentials(_ACCESS_KEY, _SECRET_KEY);
419                    }
420            }
421    
422            protected String getFileName(String key) {
423                    int x = key.indexOf(CharPool.SLASH);
424    
425                    x = key.indexOf(CharPool.SLASH, x + 1);
426    
427                    int y = key.lastIndexOf(CharPool.SLASH);
428    
429                    return key.substring(x + 1, y);
430            }
431    
432            protected String getHeadVersionLabel(
433                            long companyId, long repositoryId, String fileName)
434                    throws PortalException, S3ServiceException {
435    
436                    S3Object[] s3Objects = _s3Service.listObjects(
437                            _s3Bucket, getKey(companyId, repositoryId, fileName), null);
438    
439                    String[] keys = new String[s3Objects.length];
440    
441                    for (int i = 0; i < s3Objects.length; i++) {
442                            S3Object s3Object = s3Objects[i];
443    
444                            keys[i] = s3Object.getKey();
445                    }
446    
447                    if (keys.length > 0) {
448                            Arrays.sort(keys);
449    
450                            String headKey = keys[keys.length - 1];
451    
452                            int x = headKey.lastIndexOf(CharPool.SLASH);
453    
454                            return headKey.substring(x + 1, headKey.length());
455                    }
456                    else {
457                            throw new NoSuchFileException(fileName);
458                    }
459            }
460    
461            protected String getKey(long companyId, long repositoryId) {
462                    StringBundler sb = new StringBundler(4);
463    
464                    sb.append(companyId);
465                    sb.append(StringPool.SLASH);
466                    sb.append(repositoryId);
467                    sb.append(StringPool.SLASH);
468    
469                    return sb.toString();
470            }
471    
472            protected String getKey(
473                    long companyId, long repositoryId, String fileName) {
474    
475                    StringBundler sb = new StringBundler(6);
476    
477                    sb.append(companyId);
478                    sb.append(StringPool.SLASH);
479                    sb.append(repositoryId);
480                    sb.append(StringPool.SLASH);
481                    sb.append(fileName);
482                    sb.append(StringPool.SLASH);
483    
484                    return sb.toString();
485            }
486    
487            protected String getKey(
488                    long companyId, long repositoryId, String fileName,
489                    String versionLabel) {
490    
491                    StringBundler sb = new StringBundler(7);
492    
493                    sb.append(companyId);
494                    sb.append(StringPool.SLASH);
495                    sb.append(repositoryId);
496                    sb.append(StringPool.SLASH);
497                    sb.append(fileName);
498                    sb.append(StringPool.SLASH);
499                    sb.append(versionLabel);
500    
501                    return sb.toString();
502            }
503    
504            protected S3Bucket getS3Bucket() throws S3ServiceException {
505                    if (Validator.isNull(_BUCKET_NAME)) {
506                            throw new S3ServiceException("S3 bucket name is not set");
507                    }
508                    else {
509                            return getS3Service().createBucket(_BUCKET_NAME);
510                    }
511            }
512    
513            protected S3Service getS3Service() throws S3ServiceException {
514                    AWSCredentials credentials = getAWSCredentials();
515    
516                    return new RestS3Service(credentials);
517            }
518    
519            private static final String _ACCESS_KEY = PropsUtil.get(
520                    PropsKeys.DL_STORE_S3_ACCESS_KEY);
521    
522            private static final String _BUCKET_NAME = PropsUtil.get(
523                    PropsKeys.DL_STORE_S3_BUCKET_NAME);
524    
525            private static final String _SECRET_KEY = PropsUtil.get(
526                    PropsKeys.DL_STORE_S3_SECRET_KEY);
527    
528            private static Log _log = LogFactoryUtil.getLog(S3Store.class);
529    
530            private S3Bucket _s3Bucket;
531            private S3Service _s3Service;
532    
533    }