1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet.softwarecatalog.service.impl;
16  
17  import com.liferay.portal.kernel.exception.PortalException;
18  import com.liferay.portal.kernel.exception.SystemException;
19  import com.liferay.portal.kernel.plugin.Version;
20  import com.liferay.portal.kernel.search.Indexer;
21  import com.liferay.portal.kernel.search.IndexerRegistryUtil;
22  import com.liferay.portal.kernel.servlet.ImageServletTokenUtil;
23  import com.liferay.portal.kernel.util.OrderByComparator;
24  import com.liferay.portal.kernel.util.StringPool;
25  import com.liferay.portal.kernel.util.StringUtil;
26  import com.liferay.portal.kernel.util.Time;
27  import com.liferay.portal.kernel.util.Validator;
28  import com.liferay.portal.kernel.workflow.WorkflowConstants;
29  import com.liferay.portal.kernel.xml.Document;
30  import com.liferay.portal.kernel.xml.Element;
31  import com.liferay.portal.kernel.xml.SAXReaderUtil;
32  import com.liferay.portal.model.ResourceConstants;
33  import com.liferay.portal.model.User;
34  import com.liferay.portal.plugin.ModuleId;
35  import com.liferay.portal.service.ServiceContext;
36  import com.liferay.portal.util.PropsValues;
37  import com.liferay.portlet.softwarecatalog.DuplicateProductEntryModuleIdException;
38  import com.liferay.portlet.softwarecatalog.ProductEntryAuthorException;
39  import com.liferay.portlet.softwarecatalog.ProductEntryLicenseException;
40  import com.liferay.portlet.softwarecatalog.ProductEntryNameException;
41  import com.liferay.portlet.softwarecatalog.ProductEntryPageURLException;
42  import com.liferay.portlet.softwarecatalog.ProductEntryScreenshotsException;
43  import com.liferay.portlet.softwarecatalog.ProductEntryShortDescriptionException;
44  import com.liferay.portlet.softwarecatalog.ProductEntryTypeException;
45  import com.liferay.portlet.softwarecatalog.model.SCFrameworkVersion;
46  import com.liferay.portlet.softwarecatalog.model.SCLicense;
47  import com.liferay.portlet.softwarecatalog.model.SCProductEntry;
48  import com.liferay.portlet.softwarecatalog.model.SCProductScreenshot;
49  import com.liferay.portlet.softwarecatalog.model.SCProductVersion;
50  import com.liferay.portlet.softwarecatalog.service.base.SCProductEntryLocalServiceBaseImpl;
51  import com.liferay.util.xml.DocUtil;
52  
53  import java.util.Date;
54  import java.util.Iterator;
55  import java.util.List;
56  import java.util.Properties;
57  
58  /**
59   * <a href="SCProductEntryLocalServiceImpl.java.html"><b><i>View Source</i></b>
60   * </a>
61   *
62   * @author Jorge Ferrer
63   * @author Brian Wing Shun Chan
64   * @author Raymond Augé
65   */
66  public class SCProductEntryLocalServiceImpl
67      extends SCProductEntryLocalServiceBaseImpl {
68  
69      public SCProductEntry addProductEntry(
70              long userId, String name, String type, String tags,
71              String shortDescription, String longDescription, String pageURL,
72              String author, String repoGroupId, String repoArtifactId,
73              long[] licenseIds, List<byte[]> thumbnails, List<byte[]> fullImages,
74              ServiceContext serviceContext)
75          throws PortalException, SystemException {
76  
77          // Product entry
78  
79          User user = userPersistence.findByPrimaryKey(userId);
80          long groupId = serviceContext.getScopeGroupId();
81          tags = getTags(tags);
82          repoGroupId = repoGroupId.trim().toLowerCase();
83          repoArtifactId = repoArtifactId.trim().toLowerCase();
84          Date now = new Date();
85  
86          validate(
87              0, name, type, shortDescription, pageURL, author, repoGroupId,
88              repoArtifactId, licenseIds, thumbnails, fullImages);
89  
90          long productEntryId = counterLocalService.increment();
91  
92          SCProductEntry productEntry = scProductEntryPersistence.create(
93              productEntryId);
94  
95          productEntry.setGroupId(groupId);
96          productEntry.setCompanyId(user.getCompanyId());
97          productEntry.setUserId(user.getUserId());
98          productEntry.setUserName(user.getFullName());
99          productEntry.setCreateDate(now);
100         productEntry.setModifiedDate(now);
101         productEntry.setName(name);
102         productEntry.setType(type);
103         productEntry.setTags(tags);
104         productEntry.setShortDescription(shortDescription);
105         productEntry.setLongDescription(longDescription);
106         productEntry.setPageURL(pageURL);
107         productEntry.setAuthor(author);
108         productEntry.setRepoGroupId(repoGroupId);
109         productEntry.setRepoArtifactId(repoArtifactId);
110 
111         scProductEntryPersistence.update(productEntry, false);
112 
113         // Resources
114 
115         if (serviceContext.getAddCommunityPermissions() ||
116             serviceContext.getAddGuestPermissions()) {
117 
118             addProductEntryResources(
119                 productEntry, serviceContext.getAddCommunityPermissions(),
120                 serviceContext.getAddGuestPermissions());
121         }
122         else {
123             addProductEntryResources(
124                 productEntry, serviceContext.getCommunityPermissions(),
125                 serviceContext.getGuestPermissions());
126         }
127 
128         // Licenses
129 
130         scProductEntryPersistence.setSCLicenses(productEntryId, licenseIds);
131 
132         // Product screenshots
133 
134         saveProductScreenshots(productEntry, thumbnails, fullImages);
135 
136         // Message boards
137 
138         if (PropsValues.SC_PRODUCT_COMMENTS_ENABLED) {
139             mbMessageLocalService.addDiscussionMessage(
140                 userId, productEntry.getUserName(), groupId,
141                 SCProductEntry.class.getName(), productEntryId,
142                 WorkflowConstants.ACTION_PUBLISH);
143         }
144 
145         // Indexer
146 
147         Indexer indexer = IndexerRegistryUtil.getIndexer(SCProductEntry.class);
148 
149         indexer.reindex(productEntry);
150 
151         return productEntry;
152     }
153 
154     public void addProductEntryResources(
155             long productEntryId, boolean addCommunityPermissions,
156             boolean addGuestPermissions)
157         throws PortalException, SystemException {
158 
159         SCProductEntry productEntry =
160             scProductEntryPersistence.findByPrimaryKey(productEntryId);
161 
162         addProductEntryResources(
163             productEntry, addCommunityPermissions, addGuestPermissions);
164     }
165 
166     public void addProductEntryResources(
167             long productEntryId, String[] communityPermissions,
168             String[] guestPermissions)
169         throws PortalException, SystemException {
170 
171         SCProductEntry productEntry =
172             scProductEntryPersistence.findByPrimaryKey(productEntryId);
173 
174         addProductEntryResources(
175             productEntry, communityPermissions, guestPermissions);
176     }
177 
178     public void addProductEntryResources(
179             SCProductEntry productEntry, boolean addCommunityPermissions,
180             boolean addGuestPermissions)
181         throws PortalException, SystemException {
182 
183         resourceLocalService.addResources(
184             productEntry.getCompanyId(), productEntry.getGroupId(),
185             productEntry.getUserId(), SCProductEntry.class.getName(),
186             productEntry.getProductEntryId(), false, addCommunityPermissions,
187             addGuestPermissions);
188     }
189 
190     public void addProductEntryResources(
191             SCProductEntry productEntry, String[] communityPermissions,
192             String[] guestPermissions)
193         throws PortalException, SystemException {
194 
195         resourceLocalService.addModelResources(
196             productEntry.getCompanyId(), productEntry.getGroupId(),
197             productEntry.getUserId(), SCProductEntry.class.getName(),
198             productEntry.getProductEntryId(), communityPermissions,
199             guestPermissions);
200     }
201 
202     public void deleteProductEntries(long groupId)
203         throws PortalException, SystemException {
204 
205         List<SCProductEntry> productEntries =
206             scProductEntryPersistence.findByGroupId(groupId);
207 
208         for (SCProductEntry productEntry : productEntries) {
209             deleteProductEntry(productEntry);
210         }
211     }
212 
213     public void deleteProductEntry(long productEntryId)
214         throws PortalException, SystemException {
215 
216         SCProductEntry productEntry =
217             scProductEntryPersistence.findByPrimaryKey(productEntryId);
218 
219         deleteProductEntry(productEntry);
220     }
221 
222     public void deleteProductEntry(SCProductEntry productEntry)
223         throws PortalException, SystemException {
224 
225         // Product entry
226 
227         scProductEntryPersistence.remove(productEntry);
228 
229         // Resources
230 
231         resourceLocalService.deleteResource(
232             productEntry.getCompanyId(), SCProductEntry.class.getName(),
233             ResourceConstants.SCOPE_INDIVIDUAL,
234             productEntry.getProductEntryId());
235 
236         // Product screenshots
237 
238         scProductScreenshotLocalService.deleteProductScreenshots(
239             productEntry.getProductEntryId());
240 
241         // Product versions
242 
243         scProductVersionLocalService.deleteProductVersions(
244             productEntry.getProductEntryId());
245 
246         // Message boards
247 
248         mbMessageLocalService.deleteDiscussionMessages(
249             SCProductEntry.class.getName(), productEntry.getProductEntryId());
250 
251         // Ratings
252 
253         ratingsStatsLocalService.deleteStats(
254             SCProductEntry.class.getName(), productEntry.getProductEntryId());
255 
256         // Indexer
257 
258         Indexer indexer = IndexerRegistryUtil.getIndexer(SCProductEntry.class);
259 
260         indexer.delete(productEntry);
261     }
262 
263     public List<SCProductEntry> getCompanyProductEntries(
264             long companyId, int start, int end)
265         throws SystemException {
266 
267         return scProductEntryPersistence.findByCompanyId(companyId, start, end);
268     }
269 
270     public int getCompanyProductEntriesCount(long companyId)
271         throws SystemException {
272 
273         return scProductEntryPersistence.countByCompanyId(companyId);
274     }
275 
276     public List<SCProductEntry> getProductEntries(
277             long groupId, int start, int end)
278         throws SystemException {
279 
280         return scProductEntryPersistence.findByGroupId(groupId, start, end);
281     }
282 
283     public List<SCProductEntry> getProductEntries(
284             long groupId, int start, int end, OrderByComparator obc)
285         throws SystemException {
286 
287         return scProductEntryPersistence.findByGroupId(
288             groupId, start, end, obc);
289     }
290 
291     public List<SCProductEntry> getProductEntries(
292             long groupId, long userId, int start, int end)
293         throws SystemException {
294 
295         return scProductEntryPersistence.findByG_U(groupId, userId, start, end);
296     }
297 
298     public List<SCProductEntry> getProductEntries(
299             long groupId, long userId, int start, int end,
300             OrderByComparator obc)
301         throws SystemException {
302 
303         return scProductEntryPersistence.findByG_U(
304             groupId, userId, start, end, obc);
305     }
306 
307     public int getProductEntriesCount(long groupId)
308         throws SystemException {
309 
310         return scProductEntryPersistence.countByGroupId(groupId);
311     }
312 
313     public int getProductEntriesCount(long groupId, long userId)
314         throws SystemException {
315 
316         return scProductEntryPersistence.countByG_U(groupId, userId);
317     }
318 
319     public SCProductEntry getProductEntry(long productEntryId)
320         throws PortalException, SystemException {
321 
322         return scProductEntryPersistence.findByPrimaryKey(productEntryId);
323     }
324 
325     public String getRepositoryXML(
326             long groupId, String baseImageURL, Date oldestDate,
327             int maxNumOfVersions, Properties repoSettings)
328         throws SystemException {
329 
330         return getRepositoryXML(
331             groupId, null, baseImageURL, oldestDate, maxNumOfVersions,
332             repoSettings);
333     }
334 
335     public String getRepositoryXML(
336             long groupId, String version, String baseImageURL, Date oldestDate,
337             int maxNumOfVersions, Properties repoSettings)
338         throws SystemException {
339 
340         Document doc = SAXReaderUtil.createDocument();
341 
342         doc.setXMLEncoding(StringPool.UTF8);
343 
344         Element root = doc.addElement("plugin-repository");
345 
346         Element settingsEl = root.addElement("settings");
347 
348         populateSettingsElement(settingsEl, repoSettings);
349 
350         List<SCProductEntry> productEntries =
351             scProductEntryPersistence.findByGroupId(groupId);
352 
353         for (SCProductEntry productEntry : productEntries) {
354             if (Validator.isNull(productEntry.getRepoGroupId()) ||
355                 Validator.isNull(productEntry.getRepoArtifactId())) {
356 
357                 continue;
358             }
359 
360             List<SCProductVersion> productVersions =
361                 scProductVersionPersistence.findByProductEntryId(
362                     productEntry.getProductEntryId());
363 
364             for (int i = 0; i < productVersions.size(); i++) {
365                 SCProductVersion productVersion = productVersions.get(i);
366 
367                 if ((maxNumOfVersions > 0) && (maxNumOfVersions < (i + 1))) {
368                     break;
369                 }
370 
371                 if (!productVersion.isRepoStoreArtifact()) {
372                     continue;
373                 }
374 
375                 if ((oldestDate != null) &&
376                     (oldestDate.after(productVersion.getModifiedDate()))) {
377 
378                     continue;
379                 }
380 
381                 if (Validator.isNotNull(version) &&
382                     !isVersionSupported(
383                         version, productVersion.getFrameworkVersions())) {
384 
385                     continue;
386                 }
387 
388                 Element el = root.addElement("plugin-package");
389 
390                 populatePluginPackageElement(
391                     el, productEntry, productVersion, baseImageURL);
392             }
393         }
394 
395         return doc.asXML();
396     }
397 
398     public SCProductEntry updateProductEntry(
399             long productEntryId, String name, String type, String tags,
400             String shortDescription, String longDescription, String pageURL,
401             String author, String repoGroupId, String repoArtifactId,
402             long[] licenseIds, List<byte[]> thumbnails, List<byte[]> fullImages)
403         throws PortalException, SystemException {
404 
405         // Product entry
406 
407         tags = getTags(tags);
408         repoGroupId = repoGroupId.trim().toLowerCase();
409         repoArtifactId = repoArtifactId.trim().toLowerCase();
410         Date now = new Date();
411 
412         validate(
413             productEntryId, name, type, shortDescription, pageURL, author,
414             repoGroupId, repoArtifactId, licenseIds, thumbnails, fullImages);
415 
416         SCProductEntry productEntry =
417             scProductEntryPersistence.findByPrimaryKey(productEntryId);
418 
419         productEntry.setModifiedDate(now);
420         productEntry.setName(name);
421         productEntry.setType(type);
422         productEntry.setTags(tags);
423         productEntry.setShortDescription(shortDescription);
424         productEntry.setLongDescription(longDescription);
425         productEntry.setPageURL(pageURL);
426         productEntry.setAuthor(author);
427         productEntry.setRepoGroupId(repoGroupId);
428         productEntry.setRepoArtifactId(repoArtifactId);
429 
430         scProductEntryPersistence.update(productEntry, false);
431 
432         // Licenses
433 
434         scProductEntryPersistence.setSCLicenses(productEntryId, licenseIds);
435 
436         // Product screenshots
437 
438         if (thumbnails.size() == 0) {
439             scProductScreenshotLocalService.deleteProductScreenshots(
440                 productEntryId);
441         }
442         else {
443             saveProductScreenshots(productEntry, thumbnails, fullImages);
444         }
445 
446         // Indexer
447 
448         Indexer indexer = IndexerRegistryUtil.getIndexer(SCProductEntry.class);
449 
450         indexer.reindex(productEntry);
451 
452         return productEntry;
453     }
454 
455     protected String getTags(String tags) {
456         tags = tags.trim().toLowerCase();
457 
458         return StringUtil.merge(StringUtil.split(tags), ", ");
459     }
460 
461     protected boolean isVersionSupported(
462         String version, List<SCFrameworkVersion> frameworkVersions) {
463 
464         Version currentVersion = Version.getInstance(version);
465 
466         for (SCFrameworkVersion frameworkVersion : frameworkVersions) {
467             Version supportedVersion = Version.getInstance(
468                 frameworkVersion.getName());
469 
470             if (supportedVersion.includes(currentVersion)) {
471                 return true;
472             }
473         }
474 
475         return false;
476     }
477 
478     protected void populatePluginPackageElement(
479             Element el, SCProductEntry productEntry,
480             SCProductVersion productVersion, String baseImageURL)
481         throws SystemException {
482 
483         DocUtil.add(el, "name", productEntry.getName());
484 
485         String moduleId = ModuleId.toString(
486             productEntry.getRepoGroupId(), productEntry.getRepoArtifactId(),
487             productVersion.getVersion(), "war");
488 
489         DocUtil.add(el, "module-id", moduleId);
490 
491         DocUtil.add(
492             el, "modified-date",
493             Time.getRFC822(productVersion.getModifiedDate()));
494 
495         Element typesEl = el.addElement("types");
496 
497         DocUtil.add(typesEl, "type", productEntry.getType());
498 
499         Element tagsEl = el.addElement("tags");
500 
501         String[] tags = StringUtil.split(productEntry.getTags());
502 
503         for (int i = 0; i < tags.length; i++) {
504             DocUtil.add(tagsEl, "tag", tags[i]);
505         }
506 
507         DocUtil.add(
508             el, "short-description", productEntry.getShortDescription());
509 
510         if (Validator.isNotNull(productEntry.getLongDescription())) {
511             DocUtil.add(
512                 el, "long-description", productEntry.getLongDescription());
513         }
514 
515         if (Validator.isNotNull(productVersion.getChangeLog())) {
516             DocUtil.add(el, "change-log", productVersion.getChangeLog());
517         }
518 
519         if (Validator.isNotNull(productVersion.getDirectDownloadURL())) {
520             DocUtil.add(
521                 el, "download-url", productVersion.getDirectDownloadURL());
522         }
523 
524         DocUtil.add(el, "author", productEntry.getAuthor());
525 
526         Element screenshotsEl = el.addElement("screenshots");
527 
528         for (SCProductScreenshot screenshot : productEntry.getScreenshots()) {
529             long thumbnailId = screenshot.getThumbnailId();
530             long fullImageId = screenshot.getFullImageId();
531 
532             Element screenshotEl = screenshotsEl.addElement("screenshot");
533 
534             DocUtil.add(
535                 screenshotEl, "thumbnail-url",
536                 baseImageURL + "?img_id=" + thumbnailId + "&t=" +
537                     ImageServletTokenUtil.getToken(thumbnailId));
538             DocUtil.add(
539                 screenshotEl, "large-image-url",
540                 baseImageURL + "?img_id=" + fullImageId + "&t=" +
541                     ImageServletTokenUtil.getToken(fullImageId));
542         }
543 
544         Element licensesEl = el.addElement("licenses");
545 
546         for (SCLicense license : productEntry.getLicenses()) {
547             Element licenseEl = licensesEl.addElement("license");
548 
549             licenseEl.addText(license.getName());
550             licenseEl.addAttribute(
551                 "osi-approved", String.valueOf(license.isOpenSource()));
552         }
553 
554         Element liferayVersionsEl = el.addElement("liferay-versions");
555 
556         for (SCFrameworkVersion frameworkVersion :
557                 productVersion.getFrameworkVersions()) {
558 
559             DocUtil.add(
560                 liferayVersionsEl, "liferay-version",
561                 frameworkVersion.getName());
562         }
563     }
564 
565     protected void populateSettingsElement(
566         Element el, Properties repoSettings) {
567 
568         if (repoSettings == null) {
569             return;
570         }
571 
572         Iterator<Object> itr = repoSettings.keySet().iterator();
573 
574         while (itr.hasNext()) {
575             String key = (String)itr.next();
576 
577             Element settingEl = el.addElement("setting");
578 
579             settingEl.addAttribute("name", key);
580             settingEl.addAttribute("value", repoSettings.getProperty(key));
581         }
582     }
583 
584     protected void saveProductScreenshots(
585             SCProductEntry productEntry, List<byte[]> thumbnails,
586             List<byte[]> fullImages)
587         throws PortalException, SystemException {
588 
589         long productEntryId = productEntry.getProductEntryId();
590 
591         List<SCProductScreenshot> productScreenshots =
592             scProductScreenshotPersistence.findByProductEntryId(productEntryId);
593 
594         if (thumbnails.size() < productScreenshots.size()) {
595             for (int i = thumbnails.size(); i < productScreenshots.size();
596                     i++) {
597 
598                 SCProductScreenshot productScreenshot =
599                     productScreenshots.get(i);
600 
601                 scProductScreenshotLocalService.deleteProductScreenshot(
602                     productScreenshot);
603             }
604         }
605 
606         for (int i = 0; i < thumbnails.size(); i++) {
607             int priority = i;
608 
609             byte[] thumbnail = thumbnails.get(i);
610             byte[] fullImage = fullImages.get(i);
611 
612             SCProductScreenshot productScreenshot =
613                 scProductScreenshotPersistence.fetchByP_P(
614                     productEntryId, priority);
615 
616             if (productScreenshot == null) {
617                 long productScreenshotId = counterLocalService.increment();
618 
619                 productScreenshot = scProductScreenshotPersistence.create(
620                     productScreenshotId);
621 
622                 productScreenshot.setCompanyId(productEntry.getCompanyId());
623                 productScreenshot.setGroupId(productEntry.getGroupId());
624                 productScreenshot.setProductEntryId(productEntryId);
625                 productScreenshot.setThumbnailId(
626                     counterLocalService.increment());
627                 productScreenshot.setFullImageId(
628                     counterLocalService.increment());
629                 productScreenshot.setPriority(priority);
630 
631                 scProductScreenshotPersistence.update(productScreenshot, false);
632             }
633 
634             imageLocalService.updateImage(
635                 productScreenshot.getThumbnailId(), thumbnail);
636             imageLocalService.updateImage(
637                 productScreenshot.getFullImageId(), fullImage);
638         }
639     }
640 
641     protected void validate(
642             long productEntryId, String name, String type,
643             String shortDescription, String pageURL, String author,
644             String repoGroupId, String repoArtifactId, long[] licenseIds,
645             List<byte[]> thumbnails, List<byte[]> fullImages)
646         throws PortalException, SystemException {
647 
648         if (Validator.isNull(name)) {
649             throw new ProductEntryNameException();
650         }
651 
652         if (Validator.isNull(type)) {
653             throw new ProductEntryTypeException();
654         }
655 
656         if (Validator.isNull(shortDescription)) {
657             throw new ProductEntryShortDescriptionException();
658         }
659 
660         if (Validator.isNull(pageURL)) {
661             throw new ProductEntryPageURLException();
662         }
663         else if (!Validator.isUrl(pageURL)) {
664             throw new ProductEntryPageURLException();
665         }
666 
667         if (Validator.isNull(author)) {
668             throw new ProductEntryAuthorException();
669         }
670 
671         SCProductEntry productEntry = scProductEntryPersistence.fetchByRG_RA(
672             repoGroupId, repoArtifactId);
673 
674         if ((productEntry != null) &&
675             (productEntry.getProductEntryId() != productEntryId)) {
676 
677             throw new DuplicateProductEntryModuleIdException();
678         }
679 
680         if (licenseIds.length == 0) {
681             throw new ProductEntryLicenseException();
682         }
683 
684         if (thumbnails.size() != fullImages.size()) {
685             throw new ProductEntryScreenshotsException();
686         }
687         else {
688             Iterator<byte[]> itr = thumbnails.iterator();
689 
690             while (itr.hasNext()) {
691                 if (itr.next() == null) {
692                     throw new ProductEntryScreenshotsException();
693                 }
694             }
695 
696             itr = fullImages.iterator();
697 
698             while (itr.hasNext()) {
699                 if (itr.next() == null) {
700                     throw new ProductEntryScreenshotsException();
701                 }
702             }
703         }
704     }
705 
706 }