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