001    /**
002     * Copyright (c) 2000-2010 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.documentlibrary.util;
016    
017    import com.liferay.documentlibrary.NoSuchFileException;
018    import com.liferay.documentlibrary.model.FileModel;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.exception.SystemException;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.search.Document;
024    import com.liferay.portal.kernel.search.Indexer;
025    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
026    import com.liferay.portal.kernel.search.SearchEngineUtil;
027    import com.liferay.portal.kernel.search.SearchException;
028    import com.liferay.portal.kernel.util.CharPool;
029    import com.liferay.portal.kernel.util.FileUtil;
030    import com.liferay.portal.kernel.util.GetterUtil;
031    import com.liferay.portal.kernel.util.PropsKeys;
032    import com.liferay.portal.kernel.util.StringBundler;
033    import com.liferay.portal.kernel.util.StringPool;
034    import com.liferay.portal.kernel.util.Validator;
035    import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
036    import com.liferay.portal.service.ServiceContext;
037    import com.liferay.portal.util.PropsUtil;
038    import com.liferay.util.SystemProperties;
039    
040    import java.io.File;
041    import java.io.FileInputStream;
042    import java.io.IOException;
043    import java.io.InputStream;
044    
045    import java.util.ArrayList;
046    import java.util.Arrays;
047    import java.util.Collection;
048    import java.util.Date;
049    import java.util.HashSet;
050    import java.util.Iterator;
051    import java.util.List;
052    import java.util.Set;
053    
054    import org.jets3t.service.S3Service;
055    import org.jets3t.service.S3ServiceException;
056    import org.jets3t.service.impl.rest.httpclient.RestS3Service;
057    import org.jets3t.service.model.S3Bucket;
058    import org.jets3t.service.model.S3Object;
059    import org.jets3t.service.security.AWSCredentials;
060    
061    /**
062     * @author Brian Wing Shun Chan
063     * @author Sten Martinez
064     */
065    public class S3Hook extends BaseHook {
066    
067            public S3Hook() {
068                    try {
069                            _s3Service = getS3Service();
070                            _s3Bucket = getS3Bucket();
071                    }
072                    catch (S3ServiceException s3se) {
073                            _log.error(s3se.getMessage());
074                    }
075            }
076    
077            public void addDirectory(
078                    long companyId, long repositoryId, String dirName) {
079            }
080    
081            public void addFile(
082                            long companyId, String portletId, long groupId, long repositoryId,
083                            String fileName, long fileEntryId, String properties,
084                            Date modifiedDate, ServiceContext serviceContext, InputStream is)
085                    throws PortalException, SystemException {
086    
087                    try {
088                            S3Object s3Object = new S3Object(
089                                    _s3Bucket,
090                                    getKey(companyId, repositoryId, fileName, DEFAULT_VERSION));
091    
092                            s3Object.setDataInputStream(is);
093    
094                            _s3Service.putObject(_s3Bucket, s3Object);
095    
096                            Indexer indexer = IndexerRegistryUtil.getIndexer(
097                                    FileModel.class);
098    
099                            FileModel fileModel = new FileModel();
100    
101                            fileModel.setAssetCategoryIds(serviceContext.getAssetCategoryIds());
102                            fileModel.setAssetTagNames(serviceContext.getAssetTagNames());
103                            fileModel.setCompanyId(companyId);
104                            fileModel.setFileEntryId(fileEntryId);
105                            fileModel.setFileName(fileName);
106                            fileModel.setGroupId(groupId);
107                            fileModel.setModifiedDate(modifiedDate);
108                            fileModel.setPortletId(portletId);
109                            fileModel.setProperties(properties);
110                            fileModel.setRepositoryId(repositoryId);
111    
112                            indexer.reindex(fileModel);
113                    }
114                    catch (S3ServiceException s3se) {
115                            throw new SystemException(s3se);
116                    }
117            }
118    
119            public void checkRoot(long companyId) {
120            }
121    
122            public void deleteDirectory(
123                            long companyId, String portletId, long repositoryId, String dirName)
124                    throws SystemException {
125    
126                    try {
127                            S3Object[] s3Objects = _s3Service.listObjects(
128                                    _s3Bucket, getKey(companyId, repositoryId, dirName), 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            public void deleteFile(
142                            long companyId, String portletId, long repositoryId,
143                            String fileName)
144                    throws PortalException, SystemException {
145    
146                    try {
147                            S3Object[] s3Objects = _s3Service.listObjects(
148                                    _s3Bucket, getKey(companyId, repositoryId, fileName), null);
149    
150                            for (int i = 0; i < s3Objects.length; i++) {
151                                    S3Object s3Object = s3Objects[i];
152    
153                                    _s3Service.deleteObject(_s3Bucket, s3Object.getKey());
154                            }
155    
156                            FileModel fileModel = new FileModel();
157    
158                            fileModel.setCompanyId(companyId);
159                            fileModel.setFileName(fileName);
160                            fileModel.setPortletId(portletId);
161                            fileModel.setRepositoryId(repositoryId);
162    
163                            Indexer indexer = IndexerRegistryUtil.getIndexer(FileModel.class);
164    
165                            indexer.delete(fileModel);
166                    }
167                    catch (S3ServiceException s3se) {
168                            throw new SystemException(s3se);
169                    }
170            }
171    
172            public void deleteFile(
173                            long companyId, String portletId, long repositoryId,
174                            String fileName, String versionNumber)
175                    throws SystemException {
176    
177                    try {
178                            _s3Service.deleteObject(
179                                    _s3Bucket,
180                                    getKey(companyId, repositoryId, fileName, versionNumber));
181                    }
182                    catch (S3ServiceException s3se) {
183                            throw new SystemException(s3se);
184                    }
185            }
186    
187            public InputStream getFileAsStream(
188                            long companyId, long repositoryId, String fileName,
189                            String versionNumber)
190                    throws PortalException, SystemException {
191    
192                    try {
193                            if (Validator.isNull(versionNumber)) {
194                                    versionNumber = getHeadVersionNumber(
195                                            companyId, repositoryId, fileName);
196                            }
197    
198                            S3Object s3Object = _s3Service.getObject(
199                                    _s3Bucket,
200                                    getKey(companyId, repositoryId, fileName, versionNumber));
201    
202                            return s3Object.getDataInputStream();
203                    }
204                    catch (S3ServiceException s3se) {
205                            throw new SystemException(s3se);
206                    }
207            }
208    
209            public String[] getFileNames(
210                            long companyId, long repositoryId, String dirName)
211                    throws SystemException {
212    
213                    try {
214                            List<String> list = new ArrayList<String>();
215    
216                            S3Object[] s3Objects = _s3Service.listObjects(
217                                    _s3Bucket, getKey(companyId, repositoryId, dirName), null);
218    
219                            for (int i = 0; i < s3Objects.length; i++) {
220                                    S3Object s3Object = s3Objects[i];
221    
222                                    // Convert /${companyId}/${repositoryId}/${dirName}/${fileName}
223                                    // /${versionNumber} to /${dirName}/${fileName}
224    
225                                    String key = s3Object.getKey();
226    
227                                    int x = key.indexOf(CharPool.SLASH);
228    
229                                    x = key.indexOf(CharPool.SLASH, x + 1);
230    
231                                    int y = key.lastIndexOf(CharPool.SLASH);
232    
233                                    list.add(key.substring(x, y));
234                            }
235    
236                            return list.toArray(new String[list.size()]);
237                    }
238                    catch (S3ServiceException s3se) {
239                            throw new SystemException(s3se);
240                    }
241            }
242    
243            public long getFileSize(
244                            long companyId, long repositoryId, String fileName)
245                    throws PortalException, SystemException {
246    
247                    try {
248                            String versionNumber = getHeadVersionNumber(
249                                    companyId, repositoryId, fileName);
250    
251                            S3Object objectDetails = _s3Service.getObjectDetails(
252                                    _s3Bucket,
253                                    getKey(companyId, repositoryId, fileName, versionNumber));
254    
255                            return objectDetails.getContentLength();
256                    }
257                    catch (S3ServiceException s3se) {
258                            throw new SystemException(s3se);
259                    }
260            }
261    
262            public boolean hasFile(
263                            long companyId, long repositoryId, String fileName,
264                            String versionNumber)
265                    throws SystemException {
266    
267                    try {
268                            S3Object[] s3Objects = _s3Service.listObjects(
269                                    _s3Bucket,
270                                    getKey(companyId, repositoryId, fileName, versionNumber), null);
271    
272                            if (s3Objects.length == 0) {
273                                    return false;
274                            }
275                            else {
276                                    return true;
277                            }
278                    }
279                    catch (S3ServiceException s3se) {
280                            throw new SystemException(s3se);
281                    }
282            }
283    
284            public void move(String srcDir, String destDir) {
285            }
286    
287            public void reindex(String[] ids) throws SearchException {
288                    long companyId = GetterUtil.getLong(ids[0]);
289                    String portletId = ids[1];
290                    long groupId = GetterUtil.getLong(ids[2]);
291                    long repositoryId = GetterUtil.getLong(ids[3]);
292    
293                    Collection<Document> documents = new ArrayList<Document>();
294    
295                    try {
296                            S3Object[] searchObjects = _s3Service.listObjects(
297                                    _s3Bucket, getKey(companyId, repositoryId), null);
298    
299                            Set<String> fileNameSet = new HashSet<String>();
300    
301                            for (int i = 0; i < searchObjects.length; i++) {
302                                    S3Object currentObject = searchObjects[i];
303    
304                                    String fileName = getFileName(currentObject.getKey());
305    
306                                    fileNameSet.add(fileName);
307                            }
308    
309                            Iterator<String> itr = fileNameSet.iterator();
310    
311                            while (itr.hasNext()) {
312                                    String fileName = itr.next();
313    
314                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
315                                            FileModel.class);
316    
317                                    FileModel fileModel = new FileModel();
318    
319                                    fileModel.setCompanyId(companyId);
320                                    fileModel.setFileName(fileName);
321                                    fileModel.setGroupId(groupId);
322                                    fileModel.setPortletId(portletId);
323                                    fileModel.setRepositoryId(repositoryId);
324    
325                                    Document document = indexer.getDocument(fileModel);
326    
327                                    if (document == null) {
328                                            continue;
329                                    }
330    
331                                    documents.add(document);
332                            }
333                    }
334                    catch (S3ServiceException s3se) {
335                            throw new SearchException(s3se);
336                    }
337    
338                    SearchEngineUtil.updateDocuments(companyId, documents);
339            }
340    
341            public void updateFile(
342                            long companyId, String portletId, long groupId, long repositoryId,
343                            long newRepositoryId, String fileName, long fileEntryId)
344                    throws PortalException, SystemException {
345    
346                    try {
347                            S3Object[] s3Objects = _s3Service.listObjects(
348                                    _s3Bucket, getKey(companyId, repositoryId, fileName), null);
349    
350                            for (int i = 0; i < s3Objects.length; i++) {
351                                    S3Object oldS3Object = s3Objects[i];
352    
353                                    String oldKey = oldS3Object.getKey();
354    
355                                    oldS3Object = _s3Service.getObject(_s3Bucket, oldKey);
356    
357                                    File tempFile = new File(
358                                            SystemProperties.get(SystemProperties.TMP_DIR) +
359                                                    File.separator + PortalUUIDUtil.generate());
360    
361                                    FileUtil.write(tempFile, oldS3Object.getDataInputStream());
362    
363                                    InputStream is = new FileInputStream(tempFile);
364    
365                                    String newPrefix = getKey(companyId, newRepositoryId);
366    
367                                    int x = oldKey.indexOf(CharPool.SLASH);
368    
369                                    x = oldKey.indexOf(CharPool.SLASH, x + 1);
370    
371                                    String newKey =
372                                            newPrefix + oldKey.substring(x + 1, oldKey.length());
373    
374                                    S3Object newS3Object = new S3Object(
375                                            _s3Bucket, newKey);
376    
377                                    newS3Object.setDataInputStream(is);
378    
379                                    _s3Service.putObject(_s3Bucket, newS3Object);
380                                    _s3Service.deleteObject(_s3Bucket, oldKey);
381    
382                                    FileUtil.delete(tempFile);
383                            }
384    
385                            Indexer indexer = IndexerRegistryUtil.getIndexer(
386                                    FileModel.class);
387    
388                            FileModel fileModel = new FileModel();
389    
390                            fileModel.setCompanyId(companyId);
391                            fileModel.setFileName(fileName);
392                            fileModel.setPortletId(portletId);
393                            fileModel.setRepositoryId(repositoryId);
394    
395                            indexer.delete(fileModel);
396    
397                            fileModel.setRepositoryId(newRepositoryId);
398                            fileModel.setGroupId(groupId);
399    
400                            indexer.reindex(fileModel);
401                    }
402                    catch (IOException ioe) {
403                            throw new SystemException(ioe);
404                    }
405                    catch (S3ServiceException s3se) {
406                            throw new SystemException(s3se);
407                    }
408            }
409    
410            public void updateFile(
411                            long companyId, String portletId, long groupId, long repositoryId,
412                            String fileName, String newFileName, boolean reindex)
413                    throws PortalException, SystemException {
414    
415                    try {
416                            S3Object[] s3Objects = _s3Service.listObjects(
417                                    _s3Bucket, getKey(companyId, repositoryId, fileName), null);
418    
419                            for (int i = 0; i < s3Objects.length; i++) {
420                                    S3Object oldS3Object = s3Objects[i];
421    
422                                    String oldKey = oldS3Object.getKey();
423    
424                                    oldS3Object = _s3Service.getObject(_s3Bucket, oldKey);
425    
426                                    File tempFile = new File(
427                                            SystemProperties.get(SystemProperties.TMP_DIR) +
428                                                    File.separator + PortalUUIDUtil.generate());
429    
430                                    FileUtil.write(tempFile, oldS3Object.getDataInputStream());
431    
432                                    InputStream is = new FileInputStream(tempFile);
433    
434                                    String newPrefix = getKey(companyId, repositoryId, newFileName);
435    
436                                    int x = oldKey.indexOf(StringPool.SLASH);
437    
438                                    x = oldKey.indexOf(CharPool.SLASH, x + 1);
439    
440                                    x = oldKey.indexOf(CharPool.SLASH, x + 1);
441    
442                                    String newKey =
443                                            newPrefix + oldKey.substring(x + 1, oldKey.length());
444    
445                                    S3Object newS3Object = new S3Object(
446                                            _s3Bucket, newKey);
447    
448                                    newS3Object.setDataInputStream(is);
449    
450                                    _s3Service.putObject(_s3Bucket, newS3Object);
451                                    _s3Service.deleteObject(_s3Bucket, oldKey);
452    
453                                    FileUtil.delete(tempFile);
454                            }
455    
456                            if (reindex) {
457                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
458                                            FileModel.class);
459    
460                                    FileModel fileModel = new FileModel();
461    
462                                    fileModel.setCompanyId(companyId);
463                                    fileModel.setFileName(fileName);
464                                    fileModel.setPortletId(portletId);
465                                    fileModel.setRepositoryId(repositoryId);
466    
467                                    indexer.delete(fileModel);
468    
469                                    fileModel.setFileName(newFileName);
470                                    fileModel.setGroupId(groupId);
471    
472                                    indexer.reindex(fileModel);
473                            }
474                    }
475                    catch (IOException ioe) {
476                            throw new SystemException(ioe);
477                    }
478                    catch (S3ServiceException s3se) {
479                            throw new SystemException(s3se);
480                    }
481            }
482    
483            public void updateFile(
484                            long companyId, String portletId, long groupId, long repositoryId,
485                            String fileName, String versionNumber, String sourceFileName,
486                            long fileEntryId, String properties, Date modifiedDate,
487                            ServiceContext serviceContext, InputStream is)
488                    throws PortalException, SystemException {
489    
490                    try {
491                            S3Object s3Object = new S3Object(
492                                    _s3Bucket,
493                                    getKey(companyId, repositoryId, fileName, versionNumber));
494    
495                            s3Object.setDataInputStream(is);
496    
497                            _s3Service.putObject(_s3Bucket, s3Object);
498    
499                            Indexer indexer = IndexerRegistryUtil.getIndexer(
500                                    FileModel.class);
501    
502                            FileModel fileModel = new FileModel();
503    
504                            fileModel.setAssetCategoryIds(serviceContext.getAssetCategoryIds());
505                            fileModel.setAssetTagNames(serviceContext.getAssetTagNames());
506                            fileModel.setCompanyId(companyId);
507                            fileModel.setFileEntryId(fileEntryId);
508                            fileModel.setFileName(fileName);
509                            fileModel.setGroupId(groupId);
510                            fileModel.setModifiedDate(modifiedDate);
511                            fileModel.setPortletId(portletId);
512                            fileModel.setProperties(properties);
513                            fileModel.setRepositoryId(repositoryId);
514    
515                            indexer.reindex(fileModel);
516                    }
517                    catch (S3ServiceException s3se) {
518                            throw new SystemException(s3se);
519                    }
520            }
521    
522            protected AWSCredentials getAWSCredentials() throws S3ServiceException {
523                    if (Validator.isNull(_ACCESS_KEY) || Validator.isNull(_SECRET_KEY)) {
524                            throw new S3ServiceException(
525                                    "S3 access and secret keys are not set");
526                    }
527                    else {
528                            return new AWSCredentials(_ACCESS_KEY, _SECRET_KEY);
529                    }
530            }
531    
532            protected String getFileName(String key) {
533                    int x = key.indexOf(CharPool.SLASH);
534    
535                    x = key.indexOf(CharPool.SLASH, x + 1);
536    
537                    int y = key.lastIndexOf(CharPool.SLASH);
538    
539                    return key.substring(x + 1, y);
540            }
541    
542            protected String getHeadVersionNumber(
543                            long companyId, long repositoryId, String fileName)
544                    throws PortalException, S3ServiceException {
545    
546                    S3Object[] s3Objects = _s3Service.listObjects(
547                            _s3Bucket, getKey(companyId, repositoryId, fileName), null);
548    
549                    String[] keys = new String[s3Objects.length];
550    
551                    for (int i = 0; i < s3Objects.length; i++) {
552                            S3Object s3Object = s3Objects[i];
553    
554                            keys[i] = s3Object.getKey();
555                    }
556    
557                    if (keys.length > 0) {
558                            Arrays.sort(keys);
559    
560                            String headKey = keys[keys.length - 1];
561    
562                            int x = headKey.lastIndexOf(CharPool.SLASH);
563    
564                            return headKey.substring(x + 1, headKey.length());
565                    }
566                    else {
567                            throw new NoSuchFileException(fileName);
568                    }
569            }
570    
571            protected String getKey(long companyId, long repositoryId) {
572                    StringBundler sb = new StringBundler(4);
573    
574                    sb.append(companyId);
575                    sb.append(StringPool.SLASH);
576                    sb.append(repositoryId);
577                    sb.append(StringPool.SLASH);
578    
579                    return sb.toString();
580            }
581    
582            protected String getKey(
583                    long companyId, long repositoryId, String fileName) {
584    
585                    StringBundler sb = new StringBundler(6);
586    
587                    sb.append(companyId);
588                    sb.append(StringPool.SLASH);
589                    sb.append(repositoryId);
590                    sb.append(StringPool.SLASH);
591                    sb.append(fileName);
592                    sb.append(StringPool.SLASH);
593    
594                    return sb.toString();
595            }
596    
597            protected String getKey(
598                    long companyId, long repositoryId, String fileName,
599                    String versionNumber) {
600    
601                    StringBundler sb = new StringBundler(7);
602    
603                    sb.append(companyId);
604                    sb.append(StringPool.SLASH);
605                    sb.append(repositoryId);
606                    sb.append(StringPool.SLASH);
607                    sb.append(fileName);
608                    sb.append(StringPool.SLASH);
609                    sb.append(versionNumber);
610    
611                    return sb.toString();
612            }
613    
614            protected S3Bucket getS3Bucket() throws S3ServiceException {
615                    if (Validator.isNull(_BUCKET_NAME)) {
616                            throw new S3ServiceException("S3 bucket name is not set");
617                    }
618                    else {
619                            return getS3Service().createBucket(_BUCKET_NAME);
620                    }
621            }
622    
623            protected S3Service getS3Service() throws S3ServiceException {
624                    AWSCredentials credentials = getAWSCredentials();
625    
626                    return new RestS3Service(credentials);
627            }
628    
629            private static final String _ACCESS_KEY = PropsUtil.get(
630                    PropsKeys.DL_HOOK_S3_ACCESS_KEY);
631    
632            private static final String _BUCKET_NAME = PropsUtil.get(
633                    PropsKeys.DL_HOOK_S3_BUCKET_NAME);
634    
635            private static final String _SECRET_KEY = PropsUtil.get(
636                    PropsKeys.DL_HOOK_S3_SECRET_KEY);
637    
638            private static Log _log = LogFactoryUtil.getLog(S3Hook.class);
639    
640            private S3Bucket _s3Bucket;
641            private S3Service _s3Service;
642    
643    }