001: /**
002: * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
003: *
004: * Permission is hereby granted, free of charge, to any person obtaining a copy
005: * of this software and associated documentation files (the "Software"), to deal
006: * in the Software without restriction, including without limitation the rights
007: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008: * copies of the Software, and to permit persons to whom the Software is
009: * furnished to do so, subject to the following conditions:
010: *
011: * The above copyright notice and this permission notice shall be included in
012: * all copies or substantial portions of the Software.
013: *
014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
020: * SOFTWARE.
021: */package com.liferay.documentlibrary.util;
022:
023: import com.liferay.documentlibrary.NoSuchFileException;
024: import com.liferay.portal.PortalException;
025: import com.liferay.portal.SystemException;
026: import com.liferay.portal.kernel.search.SearchException;
027: import com.liferay.portal.kernel.util.GetterUtil;
028: import com.liferay.portal.kernel.util.StringMaker;
029: import com.liferay.portal.kernel.util.StringPool;
030: import com.liferay.portal.kernel.util.Validator;
031: import com.liferay.portal.lucene.LuceneUtil;
032: import com.liferay.portal.util.PropsUtil;
033: import com.liferay.util.FileUtil;
034: import com.liferay.util.SystemProperties;
035: import com.liferay.util.servlet.ServletResponseUtil;
036:
037: import java.io.File;
038: import java.io.FileInputStream;
039: import java.io.IOException;
040: import java.io.InputStream;
041:
042: import java.util.ArrayList;
043: import java.util.Arrays;
044: import java.util.HashSet;
045: import java.util.Iterator;
046: import java.util.List;
047: import java.util.Set;
048:
049: import org.apache.commons.id.uuid.UUID;
050: import org.apache.commons.logging.Log;
051: import org.apache.commons.logging.LogFactory;
052: import org.apache.lucene.document.Document;
053: import org.apache.lucene.index.IndexWriter;
054:
055: import org.jets3t.service.S3Service;
056: import org.jets3t.service.S3ServiceException;
057: import org.jets3t.service.impl.rest.httpclient.RestS3Service;
058: import org.jets3t.service.model.S3Bucket;
059: import org.jets3t.service.model.S3Object;
060: import org.jets3t.service.security.AWSCredentials;
061:
062: /**
063: * <a href="S3Hook.java.html"><b><i>View Source</i></b></a>
064: *
065: * @author Brian Wing Shun Chan
066: * @author Sten Martinez
067: *
068: */
069: public class S3Hook extends BaseHook {
070:
071: public S3Hook() {
072: try {
073: _s3Service = getS3Service();
074: _s3Bucket = getS3Bucket();
075: } catch (S3ServiceException s3se) {
076: _log.error(s3se.getMessage());
077: }
078: }
079:
080: public void addDirectory(long companyId, long repositoryId,
081: String dirName) throws PortalException, SystemException {
082: }
083:
084: public void addFile(long companyId, String portletId, long groupId,
085: long repositoryId, String fileName, String properties,
086: String[] tagsEntries, InputStream is)
087: throws PortalException, SystemException {
088:
089: try {
090: S3Object s3Object = new S3Object(_s3Bucket, getKey(
091: companyId, repositoryId, fileName, DEFAULT_VERSION));
092:
093: s3Object.setDataInputStream(is);
094:
095: _s3Service.putObject(_s3Bucket, s3Object);
096:
097: Indexer.addFile(companyId, portletId, groupId,
098: repositoryId, fileName, properties, tagsEntries);
099: } catch (IOException ioe) {
100: throw new SystemException(ioe);
101: } catch (S3ServiceException s3se) {
102: throw new SystemException(s3se);
103: }
104: }
105:
106: public void checkRoot(long companyId) throws SystemException {
107: }
108:
109: public void deleteDirectory(long companyId, String portletId,
110: long repositoryId, String dirName) throws PortalException,
111: SystemException {
112:
113: try {
114: S3Object[] s3Objects = _s3Service.listObjects(_s3Bucket,
115: getKey(companyId, repositoryId, dirName), null);
116:
117: for (int i = 0; i < s3Objects.length; i++) {
118: S3Object s3Object = s3Objects[i];
119:
120: _s3Service.deleteObject(_s3Bucket, s3Object.getKey());
121: }
122: } catch (S3ServiceException s3se) {
123: throw new SystemException(s3se);
124: }
125: }
126:
127: public void deleteFile(long companyId, String portletId,
128: long repositoryId, String fileName) throws PortalException,
129: SystemException {
130:
131: try {
132: S3Object[] s3Objects = _s3Service.listObjects(_s3Bucket,
133: getKey(companyId, repositoryId, fileName), null);
134:
135: for (int i = 0; i < s3Objects.length; i++) {
136: S3Object s3Object = s3Objects[i];
137:
138: _s3Service.deleteObject(_s3Bucket, s3Object.getKey());
139: }
140:
141: Indexer.deleteFile(companyId, portletId, repositoryId,
142: fileName);
143: } catch (IOException ioe) {
144: throw new SystemException(ioe);
145: } catch (S3ServiceException s3se) {
146: throw new SystemException(s3se);
147: }
148: }
149:
150: public void deleteFile(long companyId, String portletId,
151: long repositoryId, String fileName, double versionNumber)
152: throws PortalException, SystemException {
153:
154: try {
155: _s3Service.deleteObject(_s3Bucket, getKey(companyId,
156: repositoryId, fileName, versionNumber));
157: } catch (S3ServiceException s3se) {
158: throw new SystemException(s3se);
159: }
160: }
161:
162: public InputStream getFileAsStream(long companyId,
163: long repositoryId, String fileName, double versionNumber)
164: throws PortalException, SystemException {
165:
166: try {
167: if (versionNumber == 0) {
168: versionNumber = getHeadVersionNumber(companyId,
169: repositoryId, fileName);
170: }
171:
172: S3Object s3Object = _s3Service.getObject(_s3Bucket, getKey(
173: companyId, repositoryId, fileName, versionNumber));
174:
175: return s3Object.getDataInputStream();
176: } catch (S3ServiceException s3se) {
177: throw new SystemException(s3se);
178: }
179: }
180:
181: public String[] getFileNames(long companyId, long repositoryId,
182: String dirName) throws PortalException, SystemException {
183:
184: try {
185: List list = new ArrayList();
186:
187: S3Object[] s3Objects = _s3Service.listObjects(_s3Bucket,
188: getKey(companyId, repositoryId, dirName), null);
189:
190: for (int i = 0; i < s3Objects.length; i++) {
191: S3Object s3Object = s3Objects[i];
192:
193: // Convert /${companyId}/${repositoryId}/${dirName}/${fileName}
194: // /${versionNumber} to /${dirName}/${fileName}
195:
196: String key = s3Object.getKey();
197:
198: int x = key.indexOf(StringPool.SLASH);
199:
200: x = key.indexOf(StringPool.SLASH, x + 1);
201:
202: int y = key.lastIndexOf(StringPool.SLASH);
203:
204: list.add(key.substring(x, y));
205: }
206:
207: return (String[]) list.toArray(new String[0]);
208: } catch (S3ServiceException s3se) {
209: throw new SystemException(s3se);
210: }
211: }
212:
213: public long getFileSize(long companyId, long repositoryId,
214: String fileName) throws PortalException, SystemException {
215:
216: try {
217: double versionNumber = getHeadVersionNumber(companyId,
218: repositoryId, fileName);
219:
220: S3Object objectDetails = _s3Service.getObjectDetails(
221: _s3Bucket, getKey(companyId, repositoryId,
222: fileName, versionNumber));
223:
224: return objectDetails.getContentLength();
225: } catch (S3ServiceException s3se) {
226: throw new SystemException(s3se);
227: }
228: }
229:
230: public boolean hasFile(long companyId, long repositoryId,
231: String fileName, double versionNumber)
232: throws PortalException, SystemException {
233:
234: try {
235: S3Object[] s3Objects = _s3Service.listObjects(_s3Bucket,
236: getKey(companyId, repositoryId, fileName,
237: versionNumber), null);
238:
239: if (s3Objects.length == 0) {
240: return false;
241: } else {
242: return true;
243: }
244: } catch (S3ServiceException s3se) {
245: throw new SystemException(s3se);
246: }
247: }
248:
249: public void move(String srcDir, String destDir)
250: throws SystemException {
251: }
252:
253: public void reIndex(String[] ids) throws SearchException {
254: long companyId = GetterUtil.getLong(ids[0]);
255: String portletId = ids[1];
256: long groupId = GetterUtil.getLong(ids[2]);
257: long repositoryId = GetterUtil.getLong(ids[3]);
258:
259: IndexWriter writer = null;
260:
261: try {
262: writer = LuceneUtil.getWriter(companyId);
263:
264: S3Object[] searchObjects = _s3Service.listObjects(
265: _s3Bucket, getKey(companyId, repositoryId), null);
266:
267: Set fileNameSet = new HashSet();
268:
269: for (int i = 0; i < searchObjects.length; i++) {
270: S3Object currentObject = searchObjects[i];
271:
272: String fileName = (String) getFileName(currentObject
273: .getKey());
274:
275: fileNameSet.add(fileName);
276: }
277:
278: Iterator itr = fileNameSet.iterator();
279:
280: while (itr.hasNext()) {
281: String fileName = (String) itr.next();
282:
283: try {
284: Document doc = Indexer.getAddFileDocument(
285: companyId, portletId, groupId,
286: repositoryId, fileName);
287:
288: writer.addDocument(doc);
289: } catch (Exception e) {
290: _log.error("Reindexing " + fileName, e);
291: }
292: }
293: } catch (IOException ioe) {
294: throw new SearchException(ioe);
295: } catch (S3ServiceException s3se) {
296: throw new SearchException(s3se);
297: } finally {
298: try {
299: if (writer != null) {
300: LuceneUtil.write(companyId);
301: }
302: } catch (Exception e) {
303: _log.error(e);
304: }
305: }
306: }
307:
308: public void updateFile(long companyId, String portletId,
309: long groupId, long repositoryId, String fileName,
310: double versionNumber, String sourceFileName,
311: String properties, String[] tagsEntries, InputStream is)
312: throws PortalException, SystemException {
313:
314: try {
315: S3Object s3Object = new S3Object(_s3Bucket, getKey(
316: companyId, repositoryId, fileName, versionNumber));
317:
318: s3Object.setDataInputStream(is);
319:
320: _s3Service.putObject(_s3Bucket, s3Object);
321:
322: Indexer.updateFile(companyId, portletId, groupId,
323: repositoryId, fileName, properties, tagsEntries);
324: } catch (IOException ioe) {
325: throw new SystemException(ioe);
326: } catch (S3ServiceException s3se) {
327: throw new SystemException(s3se);
328: }
329: }
330:
331: public void updateFile(long companyId, String portletId,
332: long groupId, long repositoryId, long newRepositoryId,
333: String fileName) throws PortalException, SystemException {
334:
335: try {
336: S3Object[] s3Objects = _s3Service.listObjects(_s3Bucket,
337: getKey(companyId, repositoryId, fileName), null);
338:
339: for (int i = 0; i < s3Objects.length; i++) {
340: S3Object oldS3Object = s3Objects[i];
341:
342: String oldKey = oldS3Object.getKey();
343:
344: oldS3Object = _s3Service.getObject(_s3Bucket, oldKey);
345:
346: File tempFile = new File(SystemProperties
347: .get(SystemProperties.TMP_DIR)
348: + File.separator + UUID.timeUUID());
349:
350: InputStream is = null;
351:
352: try {
353: is = oldS3Object.getDataInputStream();
354:
355: FileUtil.write(tempFile, is);
356: } catch (Exception e) {
357: } finally {
358: ServletResponseUtil.cleanUp(is);
359: }
360:
361: is = new FileInputStream(tempFile);
362:
363: String newPrefix = getKey(companyId, newRepositoryId);
364:
365: int x = oldKey.indexOf(StringPool.SLASH);
366:
367: x = oldKey.indexOf(StringPool.SLASH, x + 1);
368:
369: String newKey = newPrefix
370: + oldKey.substring(x + 1, oldKey.length());
371:
372: S3Object newS3Object = new S3Object(_s3Bucket, newKey);
373:
374: newS3Object.setDataInputStream(is);
375:
376: _s3Service.putObject(_s3Bucket, newS3Object);
377: _s3Service.deleteObject(_s3Bucket, oldKey);
378:
379: FileUtil.delete(tempFile);
380: }
381:
382: Indexer.deleteFile(companyId, portletId, repositoryId,
383: fileName);
384:
385: Indexer.addFile(companyId, portletId, groupId,
386: newRepositoryId, fileName);
387: } catch (IOException ioe) {
388: throw new SystemException(ioe);
389: } catch (S3ServiceException s3se) {
390: throw new SystemException(s3se);
391: }
392: }
393:
394: protected AWSCredentials getAWSCredentials()
395: throws S3ServiceException {
396: if (Validator.isNull(_ACCESS_KEY)
397: || Validator.isNull(_SECRET_KEY)) {
398: throw new S3ServiceException(
399: "S3 access and secret keys are not set");
400: } else {
401: return new AWSCredentials(_ACCESS_KEY, _SECRET_KEY);
402: }
403: }
404:
405: protected Object getFileName(String key) {
406: int x = key.indexOf(StringPool.SLASH);
407:
408: x = key.indexOf(StringPool.SLASH, x + 1);
409:
410: int y = key.lastIndexOf(StringPool.SLASH);
411:
412: return key.substring(x + 1, y);
413: }
414:
415: protected double getHeadVersionNumber(long companyId,
416: long repositoryId, String fileName) throws PortalException,
417: S3ServiceException {
418:
419: S3Object[] s3Objects = _s3Service.listObjects(_s3Bucket,
420: getKey(companyId, repositoryId, fileName), null);
421:
422: String[] keys = new String[s3Objects.length];
423:
424: for (int i = 0; i < s3Objects.length; i++) {
425: S3Object s3Object = s3Objects[i];
426:
427: keys[i] = s3Object.getKey();
428: }
429:
430: if (keys.length > 0) {
431: Arrays.sort(keys);
432:
433: String headKey = keys[keys.length - 1];
434:
435: int x = headKey.lastIndexOf(StringPool.SLASH);
436:
437: return GetterUtil.getDouble(headKey.substring(x + 1,
438: headKey.length()));
439: } else {
440: throw new NoSuchFileException(fileName);
441: }
442: }
443:
444: protected String getKey(long companyId, long repositoryId) {
445: StringMaker sm = new StringMaker();
446:
447: sm.append(companyId);
448: sm.append(StringPool.SLASH);
449: sm.append(repositoryId);
450: sm.append(StringPool.SLASH);
451:
452: return sm.toString();
453: }
454:
455: protected String getKey(long companyId, long repositoryId,
456: String fileName) {
457:
458: StringMaker sm = new StringMaker();
459:
460: sm.append(companyId);
461: sm.append(StringPool.SLASH);
462: sm.append(repositoryId);
463: sm.append(StringPool.SLASH);
464: sm.append(fileName);
465: sm.append(StringPool.SLASH);
466:
467: return sm.toString();
468: }
469:
470: protected String getKey(long companyId, long repositoryId,
471: String fileName, double versionNumber) {
472:
473: StringMaker sm = new StringMaker();
474:
475: sm.append(companyId);
476: sm.append(StringPool.SLASH);
477: sm.append(repositoryId);
478: sm.append(StringPool.SLASH);
479: sm.append(fileName);
480: sm.append(StringPool.SLASH);
481: sm.append(versionNumber);
482:
483: return sm.toString();
484: }
485:
486: protected S3Bucket getS3Bucket() throws S3ServiceException {
487: if (Validator.isNull(_BUCKET_NAME)) {
488: throw new S3ServiceException("S3 bucket name is not set");
489: } else {
490: return getS3Service().createBucket(_BUCKET_NAME);
491: }
492: }
493:
494: protected S3Service getS3Service() throws S3ServiceException {
495: AWSCredentials credentials = getAWSCredentials();
496:
497: return new RestS3Service(credentials);
498: }
499:
500: private static final String _ACCESS_KEY = PropsUtil
501: .get(PropsUtil.DL_HOOK_S3_ACCESS_KEY);
502:
503: private static final String _SECRET_KEY = PropsUtil
504: .get(PropsUtil.DL_HOOK_S3_SECRET_KEY);
505:
506: private static final String _BUCKET_NAME = PropsUtil
507: .get(PropsUtil.DL_HOOK_S3_BUCKET_NAME);
508:
509: private static Log _log = LogFactory.getLog(S3Hook.class);
510:
511: private S3Bucket _s3Bucket;
512: private S3Service _s3Service;
513:
514: }
|