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