1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.softwarecatalog.service.impl;
24  
25  import com.liferay.portal.PortalException;
26  import com.liferay.portal.SystemException;
27  import com.liferay.portal.kernel.log.Log;
28  import com.liferay.portal.kernel.log.LogFactoryUtil;
29  import com.liferay.portal.kernel.search.BooleanClauseOccur;
30  import com.liferay.portal.kernel.search.BooleanQuery;
31  import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
32  import com.liferay.portal.kernel.search.Field;
33  import com.liferay.portal.kernel.search.Hits;
34  import com.liferay.portal.kernel.search.SearchEngineUtil;
35  import com.liferay.portal.kernel.search.SearchException;
36  import com.liferay.portal.kernel.servlet.ImageServletTokenUtil;
37  import com.liferay.portal.kernel.util.GetterUtil;
38  import com.liferay.portal.kernel.util.OrderByComparator;
39  import com.liferay.portal.kernel.util.StringPool;
40  import com.liferay.portal.kernel.util.StringUtil;
41  import com.liferay.portal.kernel.util.Time;
42  import com.liferay.portal.kernel.util.Validator;
43  import com.liferay.portal.kernel.xml.Document;
44  import com.liferay.portal.kernel.xml.Element;
45  import com.liferay.portal.kernel.xml.SAXReaderUtil;
46  import com.liferay.portal.model.ResourceConstants;
47  import com.liferay.portal.model.User;
48  import com.liferay.portal.plugin.ModuleId;
49  import com.liferay.portal.service.ServiceContext;
50  import com.liferay.portlet.softwarecatalog.DuplicateProductEntryModuleIdException;
51  import com.liferay.portlet.softwarecatalog.ProductEntryAuthorException;
52  import com.liferay.portlet.softwarecatalog.ProductEntryLicenseException;
53  import com.liferay.portlet.softwarecatalog.ProductEntryNameException;
54  import com.liferay.portlet.softwarecatalog.ProductEntryPageURLException;
55  import com.liferay.portlet.softwarecatalog.ProductEntryScreenshotsException;
56  import com.liferay.portlet.softwarecatalog.ProductEntryShortDescriptionException;
57  import com.liferay.portlet.softwarecatalog.ProductEntryTypeException;
58  import com.liferay.portlet.softwarecatalog.model.SCFrameworkVersion;
59  import com.liferay.portlet.softwarecatalog.model.SCLicense;
60  import com.liferay.portlet.softwarecatalog.model.SCProductEntry;
61  import com.liferay.portlet.softwarecatalog.model.SCProductScreenshot;
62  import com.liferay.portlet.softwarecatalog.model.SCProductVersion;
63  import com.liferay.portlet.softwarecatalog.service.base.SCProductEntryLocalServiceBaseImpl;
64  import com.liferay.portlet.softwarecatalog.util.Indexer;
65  import com.liferay.util.Version;
66  import com.liferay.util.xml.DocUtil;
67  
68  import java.net.MalformedURLException;
69  import java.net.URL;
70  
71  import java.util.Date;
72  import java.util.Iterator;
73  import java.util.List;
74  import java.util.Properties;
75  
76  /**
77   * <a href="SCProductEntryLocalServiceImpl.java.html"><b><i>View Source</i></b>
78   * </a>
79   *
80   * @author Jorge Ferrer
81   * @author Brian Wing Shun Chan
82   * @author Raymond Augé
83   *
84   */
85  public class SCProductEntryLocalServiceImpl
86      extends SCProductEntryLocalServiceBaseImpl {
87  
88      public SCProductEntry addProductEntry(
89              long userId, String name, String type, String tags,
90              String shortDescription, String longDescription, String pageURL,
91              String author, String repoGroupId, String repoArtifactId,
92              long[] licenseIds, List<byte[]> thumbnails, List<byte[]> fullImages,
93              ServiceContext serviceContext)
94          throws PortalException, SystemException {
95  
96          // Product entry
97  
98          User user = userPersistence.findByPrimaryKey(userId);
99          long groupId = serviceContext.getScopeGroupId();
100         tags = getTags(tags);
101         repoGroupId = repoGroupId.trim().toLowerCase();
102         repoArtifactId = repoArtifactId.trim().toLowerCase();
103         Date now = new Date();
104 
105         validate(
106             0, name, type, shortDescription, pageURL, author, repoGroupId,
107             repoArtifactId, licenseIds, thumbnails, fullImages);
108 
109         long productEntryId = counterLocalService.increment();
110 
111         SCProductEntry productEntry = scProductEntryPersistence.create(
112             productEntryId);
113 
114         productEntry.setGroupId(groupId);
115         productEntry.setCompanyId(user.getCompanyId());
116         productEntry.setUserId(user.getUserId());
117         productEntry.setUserName(user.getFullName());
118         productEntry.setCreateDate(now);
119         productEntry.setModifiedDate(now);
120         productEntry.setName(name);
121         productEntry.setType(type);
122         productEntry.setTags(tags);
123         productEntry.setShortDescription(shortDescription);
124         productEntry.setLongDescription(longDescription);
125         productEntry.setPageURL(pageURL);
126         productEntry.setAuthor(author);
127         productEntry.setRepoGroupId(repoGroupId);
128         productEntry.setRepoArtifactId(repoArtifactId);
129 
130         scProductEntryPersistence.update(productEntry, false);
131 
132         // Resources
133 
134         if (serviceContext.getAddCommunityPermissions() ||
135             serviceContext.getAddGuestPermissions()) {
136 
137             addProductEntryResources(
138                 productEntry, serviceContext.getAddCommunityPermissions(),
139                 serviceContext.getAddGuestPermissions());
140         }
141         else {
142             addProductEntryResources(
143                 productEntry, serviceContext.getCommunityPermissions(),
144                 serviceContext.getGuestPermissions());
145         }
146 
147         // Licenses
148 
149         scProductEntryPersistence.setSCLicenses(productEntryId, licenseIds);
150 
151         // Product screenshots
152 
153         saveProductScreenshots(productEntry, thumbnails, fullImages);
154 
155         // Indexer
156 
157         try {
158             Indexer.addProductEntry(
159                 productEntry.getCompanyId(), groupId, userId,
160                 user.getFullName(), productEntryId, name, now, StringPool.BLANK,
161                 type, shortDescription, longDescription, pageURL, repoGroupId,
162                 repoArtifactId, productEntry.getExpandoBridge());
163         }
164         catch (SearchException se) {
165             _log.error("Indexing " + productEntryId, se);
166         }
167 
168         return productEntry;
169     }
170 
171     public void addProductEntryResources(
172             long productEntryId, boolean addCommunityPermissions,
173             boolean addGuestPermissions)
174         throws PortalException, SystemException {
175 
176         SCProductEntry productEntry =
177             scProductEntryPersistence.findByPrimaryKey(productEntryId);
178 
179         addProductEntryResources(
180             productEntry, addCommunityPermissions, addGuestPermissions);
181     }
182 
183     public void addProductEntryResources(
184             SCProductEntry productEntry, boolean addCommunityPermissions,
185             boolean addGuestPermissions)
186         throws PortalException, SystemException {
187 
188         resourceLocalService.addResources(
189             productEntry.getCompanyId(), productEntry.getGroupId(),
190             productEntry.getUserId(), SCProductEntry.class.getName(),
191             productEntry.getProductEntryId(), false, addCommunityPermissions,
192             addGuestPermissions);
193     }
194 
195     public void addProductEntryResources(
196             long productEntryId, String[] communityPermissions,
197             String[] guestPermissions)
198         throws PortalException, SystemException {
199 
200         SCProductEntry productEntry =
201             scProductEntryPersistence.findByPrimaryKey(productEntryId);
202 
203         addProductEntryResources(
204             productEntry, communityPermissions, guestPermissions);
205     }
206 
207     public void addProductEntryResources(
208             SCProductEntry productEntry, String[] communityPermissions,
209             String[] guestPermissions)
210         throws PortalException, SystemException {
211 
212         resourceLocalService.addModelResources(
213             productEntry.getCompanyId(), productEntry.getGroupId(),
214             productEntry.getUserId(), SCProductEntry.class.getName(),
215             productEntry.getProductEntryId(), communityPermissions,
216             guestPermissions);
217     }
218 
219     public void deleteProductEntries(long groupId)
220         throws PortalException, SystemException {
221 
222         List<SCProductEntry> productEntries =
223             scProductEntryPersistence.findByGroupId(groupId);
224 
225         for (SCProductEntry productEntry : productEntries) {
226             deleteProductEntry(productEntry);
227         }
228     }
229 
230     public void deleteProductEntry(long productEntryId)
231         throws PortalException, SystemException {
232 
233         SCProductEntry productEntry =
234             scProductEntryPersistence.findByPrimaryKey(productEntryId);
235 
236         deleteProductEntry(productEntry);
237     }
238 
239     public void deleteProductEntry(SCProductEntry productEntry)
240         throws PortalException, SystemException {
241 
242         // Indexer
243 
244         try {
245             Indexer.deleteProductEntry(
246                 productEntry.getCompanyId(), productEntry.getProductEntryId());
247         }
248         catch (SearchException se) {
249             _log.error(
250                 "Deleting index " + productEntry.getProductEntryId(), se);
251         }
252 
253         // Product screenshots
254 
255         scProductScreenshotLocalService.deleteProductScreenshots(
256             productEntry.getProductEntryId());
257 
258         // Product versions
259 
260         scProductVersionLocalService.deleteProductVersions(
261             productEntry.getProductEntryId());
262 
263         // Ratings
264 
265         ratingsStatsLocalService.deleteStats(
266             SCProductEntry.class.getName(), productEntry.getProductEntryId());
267 
268         // Message boards
269 
270         mbMessageLocalService.deleteDiscussionMessages(
271             SCProductEntry.class.getName(), productEntry.getProductEntryId());
272 
273         // Resources
274 
275         resourceLocalService.deleteResource(
276             productEntry.getCompanyId(), SCProductEntry.class.getName(),
277             ResourceConstants.SCOPE_INDIVIDUAL,
278             productEntry.getProductEntryId());
279 
280         // Product entry
281 
282         scProductEntryPersistence.remove(productEntry);
283     }
284 
285     public SCProductEntry getProductEntry(long productEntryId)
286         throws PortalException, SystemException {
287 
288         return scProductEntryPersistence.findByPrimaryKey(productEntryId);
289     }
290 
291     public List<SCProductEntry> getProductEntries(
292             long groupId, int start, int end)
293         throws SystemException {
294 
295         return scProductEntryPersistence.findByGroupId(groupId, start, end);
296     }
297 
298     public List<SCProductEntry> getProductEntries(
299             long groupId, int start, int end, OrderByComparator obc)
300         throws SystemException {
301 
302         return scProductEntryPersistence.findByGroupId(
303             groupId, start, end, obc);
304     }
305 
306     public List<SCProductEntry> getProductEntries(
307             long groupId, long userId, int start, int end)
308         throws SystemException {
309 
310         return scProductEntryPersistence.findByG_U(groupId, userId, start, end);
311     }
312 
313     public List<SCProductEntry> getProductEntries(
314             long groupId, long userId, int start, int end,
315             OrderByComparator obc)
316         throws SystemException {
317 
318         return scProductEntryPersistence.findByG_U(
319             groupId, userId, start, end, obc);
320     }
321 
322     public int getProductEntriesCount(long groupId)
323         throws SystemException {
324 
325         return scProductEntryPersistence.countByGroupId(groupId);
326     }
327 
328     public int getProductEntriesCount(long groupId, long userId)
329         throws SystemException {
330 
331         return scProductEntryPersistence.countByG_U(groupId, userId);
332     }
333 
334     public String getRepositoryXML(
335             long groupId, String baseImageURL, Date oldestDate,
336             int maxNumOfVersions, Properties repoSettings)
337         throws SystemException {
338 
339         return getRepositoryXML(
340             groupId, null, baseImageURL, oldestDate, maxNumOfVersions,
341             repoSettings);
342     }
343 
344     public String getRepositoryXML(
345             long groupId, String version, String baseImageURL, Date oldestDate,
346             int maxNumOfVersions, Properties repoSettings)
347         throws SystemException {
348 
349         Document doc = SAXReaderUtil.createDocument();
350 
351         doc.setXMLEncoding(StringPool.UTF8);
352 
353         Element root = doc.addElement("plugin-repository");
354 
355         Element settingsEl = root.addElement("settings");
356 
357         populateSettingsElement(settingsEl, repoSettings);
358 
359         List<SCProductEntry> productEntries =
360             scProductEntryPersistence.findByGroupId(groupId);
361 
362         for (SCProductEntry productEntry : productEntries) {
363             if (Validator.isNull(productEntry.getRepoGroupId()) ||
364                 Validator.isNull(productEntry.getRepoArtifactId())) {
365 
366                 continue;
367             }
368 
369             List<SCProductVersion> productVersions =
370                 scProductVersionPersistence.findByProductEntryId(
371                     productEntry.getProductEntryId());
372 
373             for (int i = 0; i < productVersions.size(); i++) {
374                 SCProductVersion productVersion = productVersions.get(i);
375 
376                 if ((maxNumOfVersions > 0) && (maxNumOfVersions < (i + 1))) {
377                     break;
378                 }
379 
380                 if (!productVersion.isRepoStoreArtifact()) {
381                     continue;
382                 }
383 
384                 if ((oldestDate != null) &&
385                     (oldestDate.after(productVersion.getModifiedDate()))) {
386 
387                     continue;
388                 }
389 
390                 if (Validator.isNotNull(version) &&
391                     !isVersionSupported(
392                         version, productVersion.getFrameworkVersions())) {
393 
394                     continue;
395                 }
396 
397                 Element el = root.addElement("plugin-package");
398 
399                 populatePluginPackageElement(
400                     el, productEntry, productVersion, baseImageURL);
401             }
402         }
403 
404         return doc.asXML();
405     }
406 
407     public void reIndex(long productEntryId) throws SystemException {
408         if (SearchEngineUtil.isIndexReadOnly()) {
409             return;
410         }
411 
412         SCProductEntry productEntry =
413             scProductEntryPersistence.fetchByPrimaryKey(productEntryId);
414 
415         if (productEntry == null) {
416             return;
417         }
418 
419         String version = StringPool.BLANK;
420 
421         SCProductVersion latestProductVersion = productEntry.getLatestVersion();
422 
423         if (latestProductVersion != null) {
424             version = latestProductVersion.getVersion();
425         }
426 
427         try {
428             Indexer.updateProductEntry(
429                 productEntry.getCompanyId(), productEntry.getGroupId(),
430                 productEntry.getUserId(), productEntry.getUserName(),
431                 productEntryId, productEntry.getName(),
432                 productEntry.getModifiedDate(), version, productEntry.getType(),
433                 productEntry.getShortDescription(),
434                 productEntry.getLongDescription(), productEntry.getPageURL(),
435                 productEntry.getRepoGroupId(), productEntry.getRepoArtifactId(),
436                 productEntry.getExpandoBridge());
437         }
438         catch (SearchException se) {
439             _log.error("Reindexing " + productEntryId, se);
440         }
441     }
442 
443     public void reIndex(String[] ids) throws SystemException {
444         if (SearchEngineUtil.isIndexReadOnly()) {
445             return;
446         }
447 
448         long companyId = GetterUtil.getLong(ids[0]);
449 
450         try {
451             List<SCProductEntry> productEntries =
452                 scProductEntryPersistence.findByCompanyId(companyId);
453 
454             for (SCProductEntry productEntry : productEntries) {
455                 long productEntryId = productEntry.getProductEntryId();
456 
457                 String version = StringPool.BLANK;
458 
459                 SCProductVersion latestProductVersion =
460                     productEntry.getLatestVersion();
461 
462                 if (latestProductVersion != null) {
463                     version = latestProductVersion.getVersion();
464                 }
465 
466                 try {
467                     Indexer.updateProductEntry(
468                         companyId, productEntry.getGroupId(),
469                         productEntry.getUserId(), productEntry.getUserName(),
470                         productEntryId, productEntry.getName(),
471                         productEntry.getModifiedDate(), version,
472                         productEntry.getType(),
473                         productEntry.getShortDescription(),
474                         productEntry.getLongDescription(),
475                         productEntry.getPageURL(),
476                         productEntry.getRepoGroupId(),
477                         productEntry.getRepoArtifactId(),
478                         productEntry.getExpandoBridge());
479                 }
480                 catch (SearchException se) {
481                     _log.error("Reindexing " + productEntryId, se);
482                 }
483             }
484         }
485         catch (SystemException se) {
486             throw se;
487         }
488         catch (Exception e) {
489             throw new SystemException(e);
490         }
491     }
492 
493     public Hits search(
494             long companyId, long groupId, String keywords, String type,
495             int start, int end)
496         throws SystemException {
497 
498         try {
499             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
500 
501             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
502             contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
503 
504             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
505 
506             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
507 
508             if (Validator.isNotNull(keywords)) {
509                 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
510 
511                 searchQuery.addTerm(Field.USER_NAME, keywords);
512                 searchQuery.addTerm(Field.TITLE, keywords);
513                 searchQuery.addTerm(Field.CONTENT, keywords);
514 
515                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
516             }
517 
518             if (Validator.isNotNull(type)) {
519                 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
520 
521                 searchQuery.addRequiredTerm("type", type);
522 
523                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
524             }
525 
526             return SearchEngineUtil.search(companyId, fullQuery, start, end);
527         }
528         catch (Exception e) {
529             throw new SystemException(e);
530         }
531     }
532 
533     public SCProductEntry updateProductEntry(
534             long productEntryId, String name, String type, String tags,
535             String shortDescription, String longDescription, String pageURL,
536             String author, String repoGroupId, String repoArtifactId,
537             long[] licenseIds, List<byte[]> thumbnails, List<byte[]> fullImages)
538         throws PortalException, SystemException {
539 
540         // Product entry
541 
542         tags = getTags(tags);
543         repoGroupId = repoGroupId.trim().toLowerCase();
544         repoArtifactId = repoArtifactId.trim().toLowerCase();
545         Date now = new Date();
546 
547         validate(
548             productEntryId, name, type, shortDescription, pageURL, author,
549             repoGroupId, repoArtifactId, licenseIds, thumbnails, fullImages);
550 
551         SCProductEntry productEntry =
552             scProductEntryPersistence.findByPrimaryKey(productEntryId);
553 
554         productEntry.setModifiedDate(now);
555         productEntry.setName(name);
556         productEntry.setType(type);
557         productEntry.setTags(tags);
558         productEntry.setShortDescription(shortDescription);
559         productEntry.setLongDescription(longDescription);
560         productEntry.setPageURL(pageURL);
561         productEntry.setAuthor(author);
562         productEntry.setRepoGroupId(repoGroupId);
563         productEntry.setRepoArtifactId(repoArtifactId);
564 
565         scProductEntryPersistence.update(productEntry, false);
566 
567         // Licenses
568 
569         scProductEntryPersistence.setSCLicenses(productEntryId, licenseIds);
570 
571         // Product screenshots
572 
573         if (thumbnails.size() == 0) {
574             scProductScreenshotLocalService.deleteProductScreenshots(
575                 productEntryId);
576         }
577         else {
578             saveProductScreenshots(productEntry, thumbnails, fullImages);
579         }
580 
581         // Latest product version
582 
583         String version = StringPool.BLANK;
584 
585         List<SCProductVersion> productVersions =
586             scProductVersionPersistence.findByProductEntryId(
587                 productEntryId, 0, 1);
588 
589         if (productVersions.size() > 0) {
590             SCProductVersion productVersion = productVersions.get(0);
591 
592             productVersion.setModifiedDate(now);
593 
594             scProductVersionPersistence.update(productVersion, false);
595 
596             version = productVersion.getVersion();
597         }
598 
599         // Indexer
600 
601         try {
602             Indexer.updateProductEntry(
603                 productEntry.getCompanyId(), productEntry.getGroupId(),
604                 productEntry.getUserId(), productEntry.getUserName(),
605                 productEntryId, name, now, version, type, shortDescription,
606                 longDescription, pageURL, repoGroupId, repoArtifactId,
607                 productEntry.getExpandoBridge());
608         }
609         catch (SearchException se) {
610             _log.error("Indexing " + productEntryId, se);
611         }
612 
613         return productEntry;
614     }
615 
616     protected String getTags(String tags) {
617         tags = tags.trim().toLowerCase();
618 
619         return StringUtil.merge(StringUtil.split(tags), ", ");
620     }
621 
622     protected boolean isVersionSupported(
623         String version, List<SCFrameworkVersion> frameworkVersions) {
624 
625         Version currentVersion = Version.getInstance(version);
626 
627         for (SCFrameworkVersion frameworkVersion : frameworkVersions) {
628             Version supportedVersion = Version.getInstance(
629                 frameworkVersion.getName());
630 
631             if (supportedVersion.includes(currentVersion)) {
632                 return true;
633             }
634         }
635 
636         return false;
637     }
638 
639     protected void populatePluginPackageElement(
640             Element el, SCProductEntry productEntry,
641             SCProductVersion productVersion, String baseImageURL)
642         throws SystemException {
643 
644         DocUtil.add(el, "name", productEntry.getName());
645 
646         String moduleId = ModuleId.toString(
647             productEntry.getRepoGroupId(), productEntry.getRepoArtifactId(),
648             productVersion.getVersion(), "war");
649 
650         DocUtil.add(el, "module-id", moduleId);
651 
652         DocUtil.add(
653             el, "modified-date",
654             Time.getRFC822(productVersion.getModifiedDate()));
655 
656         Element typesEl = el.addElement("types");
657 
658         DocUtil.add(typesEl, "type", productEntry.getType());
659 
660         Element tagsEl = el.addElement("tags");
661 
662         String[] tags = StringUtil.split(productEntry.getTags());
663 
664         for (int i = 0; i < tags.length; i++) {
665             DocUtil.add(tagsEl, "tag", tags[i]);
666         }
667 
668         DocUtil.add(
669             el, "short-description", productEntry.getShortDescription());
670 
671         if (Validator.isNotNull(productEntry.getLongDescription())) {
672             DocUtil.add(
673                 el, "long-description", productEntry.getLongDescription());
674         }
675 
676         if (Validator.isNotNull(productVersion.getChangeLog())) {
677             DocUtil.add(el, "change-log", productVersion.getChangeLog());
678         }
679 
680         if (Validator.isNotNull(productVersion.getDirectDownloadURL())) {
681             DocUtil.add(
682                 el, "download-url", productVersion.getDirectDownloadURL());
683         }
684 
685         DocUtil.add(el, "author", productEntry.getAuthor());
686 
687         Element screenshotsEl = el.addElement("screenshots");
688 
689         for (SCProductScreenshot screenshot : productEntry.getScreenshots()) {
690             long thumbnailId = screenshot.getThumbnailId();
691             long fullImageId = screenshot.getFullImageId();
692 
693             Element screenshotEl = screenshotsEl.addElement("screenshot");
694 
695             DocUtil.add(
696                 screenshotEl, "thumbnail-url",
697                 baseImageURL + "?img_id=" + thumbnailId + "&t=" +
698                     ImageServletTokenUtil.getToken(thumbnailId));
699             DocUtil.add(
700                 screenshotEl, "large-image-url",
701                 baseImageURL + "?img_id=" + fullImageId + "&t=" +
702                     ImageServletTokenUtil.getToken(fullImageId));
703         }
704 
705         Element licensesEl = el.addElement("licenses");
706 
707         for (SCLicense license : productEntry.getLicenses()) {
708             Element licenseEl = licensesEl.addElement("license");
709 
710             licenseEl.addText(license.getName());
711             licenseEl.addAttribute(
712                 "osi-approved", String.valueOf(license.isOpenSource()));
713         }
714 
715         Element liferayVersionsEl = el.addElement("liferay-versions");
716 
717         for (SCFrameworkVersion frameworkVersion :
718                 productVersion.getFrameworkVersions()) {
719 
720             DocUtil.add(
721                 liferayVersionsEl, "liferay-version",
722                 frameworkVersion.getName());
723         }
724     }
725 
726     protected void populateSettingsElement(
727         Element el, Properties repoSettings) {
728 
729         if (repoSettings == null) {
730             return;
731         }
732 
733         Iterator<Object> itr = repoSettings.keySet().iterator();
734 
735         while (itr.hasNext()) {
736             String key = (String)itr.next();
737 
738             Element settingEl = el.addElement("setting");
739 
740             settingEl.addAttribute("name", key);
741             settingEl.addAttribute("value", repoSettings.getProperty(key));
742         }
743     }
744 
745     protected void saveProductScreenshots(
746             SCProductEntry productEntry, List<byte[]> thumbnails,
747             List<byte[]> fullImages)
748         throws PortalException, SystemException {
749 
750         long productEntryId = productEntry.getProductEntryId();
751 
752         List<SCProductScreenshot> productScreenshots =
753             scProductScreenshotPersistence.findByProductEntryId(productEntryId);
754 
755         if (thumbnails.size() < productScreenshots.size()) {
756             for (int i = thumbnails.size(); i < productScreenshots.size();
757                     i++) {
758 
759                 SCProductScreenshot productScreenshot =
760                     productScreenshots.get(i);
761 
762                 scProductScreenshotLocalService.deleteProductScreenshot(
763                     productScreenshot);
764             }
765         }
766 
767         for (int i = 0; i < thumbnails.size(); i++) {
768             int priority = i;
769 
770             byte[] thumbnail = thumbnails.get(i);
771             byte[] fullImage = fullImages.get(i);
772 
773             SCProductScreenshot productScreenshot =
774                 scProductScreenshotPersistence.fetchByP_P(
775                     productEntryId, priority);
776 
777             if (productScreenshot == null) {
778                 long productScreenshotId = counterLocalService.increment();
779 
780                 productScreenshot = scProductScreenshotPersistence.create(
781                     productScreenshotId);
782 
783                 productScreenshot.setCompanyId(productEntry.getCompanyId());
784                 productScreenshot.setGroupId(productEntry.getGroupId());
785                 productScreenshot.setProductEntryId(productEntryId);
786                 productScreenshot.setThumbnailId(
787                     counterLocalService.increment());
788                 productScreenshot.setFullImageId(
789                     counterLocalService.increment());
790                 productScreenshot.setPriority(priority);
791 
792                 scProductScreenshotPersistence.update(productScreenshot, false);
793             }
794 
795             imageLocalService.updateImage(
796                 productScreenshot.getThumbnailId(), thumbnail);
797             imageLocalService.updateImage(
798                 productScreenshot.getFullImageId(), fullImage);
799         }
800     }
801 
802     protected void validate(
803             long productEntryId, String name, String type,
804             String shortDescription, String pageURL, String author,
805             String repoGroupId, String repoArtifactId, long[] licenseIds,
806             List<byte[]> thumbnails, List<byte[]> fullImages)
807         throws PortalException, SystemException {
808 
809         if (Validator.isNull(name)) {
810             throw new ProductEntryNameException();
811         }
812 
813         if (Validator.isNull(type)) {
814             throw new ProductEntryTypeException();
815         }
816 
817         if (Validator.isNull(shortDescription)) {
818             throw new ProductEntryShortDescriptionException();
819         }
820 
821         if (Validator.isNull(pageURL)) {
822             throw new ProductEntryPageURLException();
823         }
824         else {
825             try {
826                 new URL(pageURL);
827             }
828             catch (MalformedURLException murle) {
829                 throw new ProductEntryPageURLException();
830             }
831         }
832 
833         if (Validator.isNull(author)) {
834             throw new ProductEntryAuthorException();
835         }
836 
837         SCProductEntry productEntry = scProductEntryPersistence.fetchByRG_RA(
838             repoGroupId, repoArtifactId);
839 
840         if ((productEntry != null) &&
841             (productEntry.getProductEntryId() != productEntryId)) {
842 
843             throw new DuplicateProductEntryModuleIdException();
844         }
845 
846         if (licenseIds.length == 0) {
847             throw new ProductEntryLicenseException();
848         }
849 
850         if (thumbnails.size() != fullImages.size()) {
851             throw new ProductEntryScreenshotsException();
852         }
853         else {
854             Iterator<byte[]> itr = thumbnails.iterator();
855 
856             while (itr.hasNext()) {
857                 if (itr.next() == null) {
858                     throw new ProductEntryScreenshotsException();
859                 }
860             }
861 
862             itr = fullImages.iterator();
863 
864             while (itr.hasNext()) {
865                 if (itr.next() == null) {
866                     throw new ProductEntryScreenshotsException();
867                 }
868             }
869         }
870     }
871 
872     private static Log _log =
873         LogFactoryUtil.getLog(SCProductEntryLocalServiceImpl.class);
874 
875 }