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