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