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.portlet.blogs.service.impl;
022:
023: import com.liferay.portal.PortalException;
024: import com.liferay.portal.SystemException;
025: import com.liferay.portal.kernel.search.Hits;
026: import com.liferay.portal.kernel.util.ArrayUtil;
027: import com.liferay.portal.kernel.util.ContentTypes;
028: import com.liferay.portal.kernel.util.GetterUtil;
029: import com.liferay.portal.kernel.util.OrderByComparator;
030: import com.liferay.portal.kernel.util.StringMaker;
031: import com.liferay.portal.kernel.util.Validator;
032: import com.liferay.portal.lucene.LuceneFields;
033: import com.liferay.portal.lucene.LuceneUtil;
034: import com.liferay.portal.model.Group;
035: import com.liferay.portal.model.User;
036: import com.liferay.portal.model.impl.ResourceImpl;
037: import com.liferay.portal.theme.ThemeDisplay;
038: import com.liferay.portal.util.PortalUtil;
039: import com.liferay.portlet.blogs.EntryContentException;
040: import com.liferay.portlet.blogs.EntryDisplayDateException;
041: import com.liferay.portlet.blogs.EntryTitleException;
042: import com.liferay.portlet.blogs.model.BlogsEntry;
043: import com.liferay.portlet.blogs.model.BlogsStatsUser;
044: import com.liferay.portlet.blogs.service.base.BlogsEntryLocalServiceBaseImpl;
045: import com.liferay.portlet.blogs.util.Indexer;
046: import com.liferay.util.Http;
047: import com.liferay.util.HttpUtil;
048: import com.liferay.util.Normalizer;
049: import com.liferay.util.lucene.HitsImpl;
050:
051: import java.io.IOException;
052:
053: import java.util.Date;
054: import java.util.Iterator;
055: import java.util.List;
056:
057: import org.apache.commons.logging.Log;
058: import org.apache.commons.logging.LogFactory;
059: import org.apache.lucene.document.Document;
060: import org.apache.lucene.index.IndexWriter;
061: import org.apache.lucene.search.BooleanClause;
062: import org.apache.lucene.search.BooleanQuery;
063: import org.apache.lucene.search.Searcher;
064:
065: /**
066: * <a href="BlogsEntryLocalServiceImpl.java.html"><b><i>View Source</i></b>
067: * </a>
068: *
069: * @author Brian Wing Shun Chan
070: * @author Wilson S. Man
071: *
072: */
073: public class BlogsEntryLocalServiceImpl extends
074: BlogsEntryLocalServiceBaseImpl {
075:
076: public BlogsEntry addEntry(long userId, long plid, String title,
077: String content, int displayDateMonth, int displayDateDay,
078: int displayDateYear, int displayDateHour,
079: int displayDateMinute, String[] tagsEntries,
080: boolean addCommunityPermissions,
081: boolean addGuestPermissions, ThemeDisplay themeDisplay)
082: throws PortalException, SystemException {
083:
084: return addEntry(null, userId, plid, title, content,
085: displayDateMonth, displayDateDay, displayDateYear,
086: displayDateHour, displayDateMinute, tagsEntries,
087: Boolean.valueOf(addCommunityPermissions), Boolean
088: .valueOf(addGuestPermissions), null, null,
089: themeDisplay);
090: }
091:
092: public BlogsEntry addEntry(String uuid, long userId, long plid,
093: String title, String content, int displayDateMonth,
094: int displayDateDay, int displayDateYear,
095: int displayDateHour, int displayDateMinute,
096: String[] tagsEntries, boolean addCommunityPermissions,
097: boolean addGuestPermissions, ThemeDisplay themeDisplay)
098: throws PortalException, SystemException {
099:
100: return addEntry(uuid, userId, plid, title, content,
101: displayDateMonth, displayDateDay, displayDateYear,
102: displayDateHour, displayDateMinute, tagsEntries,
103: Boolean.valueOf(addCommunityPermissions), Boolean
104: .valueOf(addGuestPermissions), null, null,
105: themeDisplay);
106: }
107:
108: public BlogsEntry addEntry(long userId, long plid, String title,
109: String content, int displayDateMonth, int displayDateDay,
110: int displayDateYear, int displayDateHour,
111: int displayDateMinute, String[] tagsEntries,
112: String[] communityPermissions, String[] guestPermissions,
113: ThemeDisplay themeDisplay) throws PortalException,
114: SystemException {
115:
116: return addEntry(null, userId, plid, title, content,
117: displayDateMonth, displayDateDay, displayDateYear,
118: displayDateHour, displayDateMinute, tagsEntries, null,
119: null, communityPermissions, guestPermissions,
120: themeDisplay);
121: }
122:
123: public BlogsEntry addEntry(String uuid, long userId, long plid,
124: String title, String content, int displayDateMonth,
125: int displayDateDay, int displayDateYear,
126: int displayDateHour, int displayDateMinute,
127: String[] tagsEntries, Boolean addCommunityPermissions,
128: Boolean addGuestPermissions, String[] communityPermissions,
129: String[] guestPermissions, ThemeDisplay themeDisplay)
130: throws PortalException, SystemException {
131:
132: // Entry
133:
134: User user = userPersistence.findByPrimaryKey(userId);
135: long groupId = PortalUtil.getPortletGroupId(plid);
136: Date now = new Date();
137:
138: Date displayDate = PortalUtil.getDate(displayDateMonth,
139: displayDateDay, displayDateYear, displayDateHour,
140: displayDateMinute, user.getTimeZone(),
141: new EntryDisplayDateException());
142:
143: validate(title, content);
144:
145: long entryId = counterLocalService.increment();
146:
147: BlogsEntry entry = blogsEntryPersistence.create(entryId);
148:
149: entry.setUuid(uuid);
150: entry.setGroupId(groupId);
151: entry.setCompanyId(user.getCompanyId());
152: entry.setUserId(user.getUserId());
153: entry.setUserName(user.getFullName());
154: entry.setCreateDate(now);
155: entry.setModifiedDate(now);
156: entry.setTitle(title);
157: entry.setUrlTitle(getUniqueUrlTitle(entryId, groupId, title));
158: entry.setContent(content);
159: entry.setDisplayDate(displayDate);
160:
161: blogsEntryPersistence.update(entry);
162:
163: // Resources
164:
165: if ((addCommunityPermissions != null)
166: && (addGuestPermissions != null)) {
167:
168: addEntryResources(entry, addCommunityPermissions
169: .booleanValue(), addGuestPermissions.booleanValue());
170: } else {
171: addEntryResources(entry, communityPermissions,
172: guestPermissions);
173: }
174:
175: // Statistics
176:
177: blogsStatsUserLocalService.updateStatsUser(entry.getGroupId(),
178: userId, now);
179:
180: // Tags
181:
182: updateTagsAsset(userId, entry, tagsEntries);
183:
184: // Lucene
185:
186: try {
187: Indexer.addEntry(entry.getCompanyId(), entry.getGroupId(),
188: userId, entryId, title, content, tagsEntries);
189: } catch (IOException ioe) {
190: _log.error("Indexing " + entryId, ioe);
191: }
192:
193: // Google
194:
195: pingGoogle(entry, themeDisplay);
196:
197: return entry;
198: }
199:
200: public void addEntryResources(long entryId,
201: boolean addCommunityPermissions, boolean addGuestPermissions)
202: throws PortalException, SystemException {
203:
204: BlogsEntry entry = blogsEntryPersistence
205: .findByPrimaryKey(entryId);
206:
207: addEntryResources(entry, addCommunityPermissions,
208: addGuestPermissions);
209: }
210:
211: public void addEntryResources(BlogsEntry entry,
212: boolean addCommunityPermissions, boolean addGuestPermissions)
213: throws PortalException, SystemException {
214:
215: resourceLocalService.addResources(entry.getCompanyId(), entry
216: .getGroupId(), entry.getUserId(), BlogsEntry.class
217: .getName(), entry.getEntryId(), false,
218: addCommunityPermissions, addGuestPermissions);
219: }
220:
221: public void addEntryResources(long entryId,
222: String[] communityPermissions, String[] guestPermissions)
223: throws PortalException, SystemException {
224:
225: BlogsEntry entry = blogsEntryPersistence
226: .findByPrimaryKey(entryId);
227:
228: addEntryResources(entry, communityPermissions, guestPermissions);
229: }
230:
231: public void addEntryResources(BlogsEntry entry,
232: String[] communityPermissions, String[] guestPermissions)
233: throws PortalException, SystemException {
234:
235: resourceLocalService.addModelResources(entry.getCompanyId(),
236: entry.getGroupId(), entry.getUserId(), BlogsEntry.class
237: .getName(), entry.getEntryId(),
238: communityPermissions, guestPermissions);
239: }
240:
241: public void deleteEntries(long groupId) throws PortalException,
242: SystemException {
243:
244: Iterator itr = blogsEntryPersistence.findByGroupId(groupId)
245: .iterator();
246:
247: while (itr.hasNext()) {
248: BlogsEntry entry = (BlogsEntry) itr.next();
249:
250: deleteEntry(entry);
251: }
252: }
253:
254: public void deleteEntry(long entryId) throws PortalException,
255: SystemException {
256:
257: BlogsEntry entry = blogsEntryPersistence
258: .findByPrimaryKey(entryId);
259:
260: deleteEntry(entry);
261: }
262:
263: public void deleteEntry(BlogsEntry entry) throws PortalException,
264: SystemException {
265:
266: // Lucene
267:
268: try {
269: Indexer.deleteEntry(entry.getCompanyId(), entry
270: .getEntryId());
271: } catch (IOException ioe) {
272: _log.error("Deleting index " + entry.getEntryId(), ioe);
273: }
274:
275: // Tags
276:
277: tagsAssetLocalService.deleteAsset(BlogsEntry.class.getName(),
278: entry.getEntryId());
279:
280: // Ratings
281:
282: ratingsStatsLocalService.deleteStats(
283: BlogsEntry.class.getName(), entry.getEntryId());
284:
285: // Message boards
286:
287: mbMessageLocalService.deleteDiscussionMessages(BlogsEntry.class
288: .getName(), entry.getEntryId());
289:
290: // Resources
291:
292: resourceLocalService.deleteResource(entry.getCompanyId(),
293: BlogsEntry.class.getName(),
294: ResourceImpl.SCOPE_INDIVIDUAL, entry.getEntryId());
295:
296: // Entry
297:
298: blogsEntryPersistence.remove(entry.getEntryId());
299: }
300:
301: public List getCompanyEntries(long companyId, int begin, int end)
302: throws SystemException {
303:
304: return blogsEntryPersistence.findByCompanyId(companyId, begin,
305: end);
306: }
307:
308: public List getCompanyEntries(long companyId, int begin, int end,
309: OrderByComparator obc) throws SystemException {
310:
311: return blogsEntryPersistence.findByCompanyId(companyId, begin,
312: end, obc);
313: }
314:
315: public int getCompanyEntriesCount(long companyId)
316: throws SystemException {
317: return blogsEntryPersistence.countByCompanyId(companyId);
318: }
319:
320: public BlogsEntry getEntry(long entryId) throws PortalException,
321: SystemException {
322:
323: return blogsEntryPersistence.findByPrimaryKey(entryId);
324: }
325:
326: public BlogsEntry getEntry(long groupId, String urlTitle)
327: throws PortalException, SystemException {
328:
329: return blogsEntryPersistence.findByG_UT(groupId, urlTitle);
330: }
331:
332: public List getGroupEntries(long groupId, int begin, int end)
333: throws SystemException {
334:
335: return blogsEntryPersistence.findByGroupId(groupId, begin, end);
336: }
337:
338: public List getGroupEntries(long groupId, int begin, int end,
339: OrderByComparator obc) throws SystemException {
340:
341: return blogsEntryPersistence.findByGroupId(groupId, begin, end,
342: obc);
343: }
344:
345: public int getGroupEntriesCount(long groupId)
346: throws SystemException {
347: return blogsEntryPersistence.countByGroupId(groupId);
348: }
349:
350: public List getGroupUserEntries(long groupId, long userId,
351: int begin, int end) throws SystemException {
352:
353: return blogsEntryPersistence.findByG_U(groupId, userId, begin,
354: end);
355: }
356:
357: public int getGroupUserEntriesCount(long groupId, long userId)
358: throws SystemException {
359:
360: return blogsEntryPersistence.countByG_U(groupId, userId);
361: }
362:
363: public List getNoAssetEntries() throws SystemException {
364: return blogsEntryFinder.findByNoAssets();
365: }
366:
367: public List getOrganizationEntries(long organizationId, int begin,
368: int end) throws SystemException {
369:
370: return blogsEntryFinder.findByOrganizationId(organizationId,
371: begin, end);
372: }
373:
374: public int getOrganizationEntriesCount(long organizationId)
375: throws SystemException {
376:
377: return blogsEntryFinder.countByOrganizationId(organizationId);
378: }
379:
380: public String getUrlTitle(long entryId, String title) {
381: String urlTitle = String.valueOf(entryId);
382:
383: title = title.trim().toLowerCase();
384:
385: if (Validator.isNull(title) || Validator.isNumber(title)
386: || title.equals("rss")) {
387:
388: return urlTitle;
389: }
390:
391: title = Normalizer.normalizeToAscii(title);
392:
393: char[] urlTitleCharArray = title.toCharArray();
394:
395: for (int i = 0; i < urlTitleCharArray.length; i++) {
396: char oldChar = urlTitleCharArray[i];
397:
398: char newChar = oldChar;
399:
400: if ((oldChar == '_') || (Validator.isChar(oldChar))
401: || (Validator.isDigit(oldChar))) {
402:
403: } else if (ArrayUtil.contains(_URL_TITLE_REPLACE_CHARS,
404: oldChar)) {
405: newChar = '_';
406: } else {
407: return urlTitle;
408: }
409:
410: if (oldChar != newChar) {
411: urlTitleCharArray[i] = newChar;
412: }
413: }
414:
415: urlTitle = new String(urlTitleCharArray);
416:
417: return urlTitle;
418: }
419:
420: public void reIndex(String[] ids) throws SystemException {
421: if (LuceneUtil.INDEX_READ_ONLY) {
422: return;
423: }
424:
425: long companyId = GetterUtil.getLong(ids[0]);
426:
427: IndexWriter writer = null;
428:
429: try {
430: writer = LuceneUtil.getWriter(companyId);
431:
432: Iterator itr = blogsEntryPersistence.findByCompanyId(
433: companyId).iterator();
434:
435: while (itr.hasNext()) {
436: BlogsEntry entry = (BlogsEntry) itr.next();
437:
438: long groupId = entry.getGroupId();
439: long userId = entry.getUserId();
440: long entryId = entry.getEntryId();
441: String title = entry.getTitle();
442: String content = entry.getContent();
443:
444: String[] tagsEntries = tagsEntryLocalService
445: .getEntryNames(BlogsEntry.class.getName(),
446: entryId);
447:
448: try {
449: Document doc = Indexer.getAddEntryDocument(
450: companyId, groupId, userId, entryId, title,
451: content, tagsEntries);
452:
453: writer.addDocument(doc);
454: } catch (Exception e1) {
455: _log.error("Reindexing " + entryId, e1);
456: }
457: }
458: } catch (SystemException se) {
459: throw se;
460: } catch (Exception e2) {
461: throw new SystemException(e2);
462: } finally {
463: try {
464: if (writer != null) {
465: LuceneUtil.write(companyId);
466: }
467: } catch (Exception e) {
468: _log.error(e);
469: }
470: }
471: }
472:
473: public Hits search(long companyId, long groupId, long userId,
474: String keywords) throws SystemException {
475:
476: Searcher searcher = null;
477:
478: try {
479: HitsImpl hits = new HitsImpl();
480:
481: BooleanQuery contextQuery = new BooleanQuery();
482:
483: LuceneUtil.addRequiredTerm(contextQuery,
484: LuceneFields.PORTLET_ID, Indexer.PORTLET_ID);
485:
486: if (groupId > 0) {
487: LuceneUtil.addRequiredTerm(contextQuery,
488: LuceneFields.GROUP_ID, groupId);
489: }
490:
491: if (userId > 0) {
492: LuceneUtil.addRequiredTerm(contextQuery,
493: LuceneFields.USER_ID, userId);
494: }
495:
496: BooleanQuery searchQuery = new BooleanQuery();
497:
498: if (Validator.isNotNull(keywords)) {
499: LuceneUtil.addTerm(searchQuery, LuceneFields.TITLE,
500: keywords);
501: LuceneUtil.addTerm(searchQuery, LuceneFields.CONTENT,
502: keywords);
503: LuceneUtil.addTerm(searchQuery, LuceneFields.TAG_ENTRY,
504: keywords);
505: }
506:
507: BooleanQuery fullQuery = new BooleanQuery();
508:
509: fullQuery.add(contextQuery, BooleanClause.Occur.MUST);
510:
511: if (searchQuery.clauses().size() > 0) {
512: fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
513: }
514:
515: searcher = LuceneUtil.getSearcher(companyId);
516:
517: hits.recordHits(searcher.search(fullQuery), searcher);
518:
519: return hits;
520: } catch (Exception e) {
521: return LuceneUtil.closeSearcher(searcher, keywords, e);
522: }
523: }
524:
525: public BlogsEntry updateEntry(long userId, long entryId,
526: String title, String content, int displayDateMonth,
527: int displayDateDay, int displayDateYear,
528: int displayDateHour, int displayDateMinute,
529: String[] tagsEntries, ThemeDisplay themeDisplay)
530: throws PortalException, SystemException {
531:
532: // Entry
533:
534: User user = userPersistence.findByPrimaryKey(userId);
535: Date now = new Date();
536:
537: Date displayDate = PortalUtil.getDate(displayDateMonth,
538: displayDateDay, displayDateYear, displayDateHour,
539: displayDateMinute, user.getTimeZone(),
540: new EntryDisplayDateException());
541:
542: validate(title, content);
543:
544: BlogsEntry entry = blogsEntryPersistence
545: .findByPrimaryKey(entryId);
546:
547: entry.setModifiedDate(now);
548: entry.setTitle(title);
549: entry.setUrlTitle(getUniqueUrlTitle(entryId,
550: entry.getGroupId(), title));
551: entry.setContent(content);
552: entry.setDisplayDate(displayDate);
553:
554: blogsEntryPersistence.update(entry);
555:
556: // Statistics
557:
558: BlogsStatsUser statsUser = blogsStatsUserPersistence
559: .fetchByG_U(entry.getGroupId(), entry.getUserId());
560:
561: if (statsUser != null) {
562: statsUser.setLastPostDate(now);
563:
564: blogsStatsUserPersistence.update(statsUser);
565: }
566:
567: // Tags
568:
569: updateTagsAsset(userId, entry, tagsEntries);
570:
571: // Lucene
572:
573: try {
574: Indexer.updateEntry(entry.getCompanyId(), entry
575: .getGroupId(), userId, entryId, title, content,
576: tagsEntries);
577: } catch (IOException ioe) {
578: _log.error("Indexing " + entryId, ioe);
579: }
580:
581: // Google
582:
583: pingGoogle(entry, themeDisplay);
584:
585: return entry;
586: }
587:
588: public void updateTagsAsset(long userId, BlogsEntry entry,
589: String[] tagsEntries) throws PortalException,
590: SystemException {
591:
592: tagsAssetLocalService.updateAsset(userId, entry.getGroupId(),
593: BlogsEntry.class.getName(), entry.getEntryId(),
594: tagsEntries, null, null, null, null,
595: ContentTypes.TEXT_HTML, entry.getTitle(), null, null,
596: null, 0, 0, null, false);
597: }
598:
599: protected String getUniqueUrlTitle(long entryId, long groupId,
600: String title) throws SystemException {
601:
602: String urlTitle = getUrlTitle(entryId, title);
603:
604: String newUrlTitle = new String(urlTitle);
605:
606: for (int i = 1;; i++) {
607: BlogsEntry entry = blogsEntryPersistence.fetchByG_UT(
608: groupId, newUrlTitle);
609:
610: if ((entry == null) || (entry.getEntryId() == entryId)) {
611: break;
612: } else {
613: newUrlTitle = urlTitle + "_" + i;
614: }
615: }
616:
617: return newUrlTitle;
618: }
619:
620: protected void pingGoogle(BlogsEntry entry,
621: ThemeDisplay themeDisplay) throws PortalException,
622: SystemException {
623:
624: if (themeDisplay == null) {
625: return;
626: }
627:
628: Group group = groupPersistence.findByPrimaryKey(entry
629: .getGroupId());
630:
631: String portalURL = PortalUtil.getPortalURL(themeDisplay);
632:
633: if ((portalURL.indexOf("://localhost") != -1)
634: || (portalURL.indexOf("://127.0.0.1") != -1)) {
635:
636: return;
637: }
638:
639: String layoutURL = PortalUtil.getLayoutURL(themeDisplay);
640:
641: StringMaker sm = new StringMaker();
642:
643: String name = group.getDescriptiveName();
644: //String url = portalURL + layoutURL + "/blogs/" + entry.getUrlTitle();
645: String url = portalURL + layoutURL + "/blogs";
646: String changesURL = portalURL + layoutURL + "/blogs/rss";
647:
648: sm.append("http://blogsearch.google.com/ping?name=");
649: sm.append(HttpUtil.encodeURL(name));
650: sm.append("&url=");
651: sm.append(HttpUtil.encodeURL(url));
652: sm.append("&changesURL=");
653: sm.append(HttpUtil.encodeURL(changesURL));
654:
655: String location = sm.toString();
656:
657: if (_log.isInfoEnabled()) {
658: _log.info("Pinging Google at " + location);
659: }
660:
661: try {
662: String response = Http.URLtoString(sm.toString());
663:
664: if (_log.isInfoEnabled()) {
665: _log.info("Google ping response: " + response);
666: }
667: } catch (IOException ioe) {
668: _log.error("Unable to ping Google at " + location, ioe);
669: }
670: }
671:
672: protected void validate(String title, String content)
673: throws PortalException {
674:
675: if (Validator.isNull(title)) {
676: throw new EntryTitleException();
677: } else if (Validator.isNull(content)) {
678: throw new EntryContentException();
679: }
680: }
681:
682: private static final char[] _URL_TITLE_REPLACE_CHARS = new char[] {
683: ' ', '.', '-', ',', '/', '\\', '\'', '\"' };
684:
685: private static Log _log = LogFactory
686: .getLog(BlogsEntryLocalServiceImpl.class);
687:
688: }
|