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