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.portal.util.PropsValues;
51  import com.liferay.portlet.softwarecatalog.DuplicateProductEntryModuleIdException;
52  import com.liferay.portlet.softwarecatalog.ProductEntryAuthorException;
53  import com.liferay.portlet.softwarecatalog.ProductEntryLicenseException;
54  import com.liferay.portlet.softwarecatalog.ProductEntryNameException;
55  import com.liferay.portlet.softwarecatalog.ProductEntryPageURLException;
56  import com.liferay.portlet.softwarecatalog.ProductEntryScreenshotsException;
57  import com.liferay.portlet.softwarecatalog.ProductEntryShortDescriptionException;
58  import com.liferay.portlet.softwarecatalog.ProductEntryTypeException;
59  import com.liferay.portlet.softwarecatalog.model.SCFrameworkVersion;
60  import com.liferay.portlet.softwarecatalog.model.SCLicense;
61  import com.liferay.portlet.softwarecatalog.model.SCProductEntry;
62  import com.liferay.portlet.softwarecatalog.model.SCProductScreenshot;
63  import com.liferay.portlet.softwarecatalog.model.SCProductVersion;
64  import com.liferay.portlet.softwarecatalog.service.base.SCProductEntryLocalServiceBaseImpl;
65  import com.liferay.portlet.softwarecatalog.util.Indexer;
66  import com.liferay.util.Version;
67  import com.liferay.util.xml.DocUtil;
68  
69  import java.net.MalformedURLException;
70  import java.net.URL;
71  
72  import java.util.Date;
73  import java.util.Iterator;
74  import java.util.List;
75  import java.util.Properties;
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         // Message boards
186 
187         if (PropsValues.SC_PRODUCT_COMMENTS_ENABLED) {
188             mbMessageLocalService.addDiscussionMessage(
189                 userId, productEntry.getUserName(),
190                 SCProductEntry.class.getName(), productEntryId);
191         }
192 
193         // Indexer
194 
195         reIndex(productEntry);
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(long productEntryId) throws SystemException {
437         if (SearchEngineUtil.isIndexReadOnly()) {
438             return;
439         }
440 
441         SCProductEntry productEntry =
442             scProductEntryPersistence.fetchByPrimaryKey(productEntryId);
443 
444         if (productEntry == null) {
445             return;
446         }
447 
448         reIndex(productEntry);
449     }
450 
451     public void reIndex(SCProductEntry productEntry) throws SystemException {
452         long companyId = productEntry.getCompanyId();
453         long groupId = productEntry.getGroupId();
454         long userId = productEntry.getUserId();
455         String userName = productEntry.getUserName();
456         long productEntryId = productEntry.getProductEntryId();
457         String name = productEntry.getName();
458         Date modifiedDate = productEntry.getModifiedDate();
459 
460         String version = StringPool.BLANK;
461 
462         SCProductVersion latestProductVersion = productEntry.getLatestVersion();
463 
464         if (latestProductVersion != null) {
465             version = latestProductVersion.getVersion();
466         }
467 
468         String type = productEntry.getType();
469         String shortDescription = productEntry.getShortDescription();
470         String longDescription = productEntry.getLongDescription();
471         String pageURL = productEntry.getPageURL();
472         String repoGroupId = productEntry.getRepoGroupId();
473         String repoArtifactId = productEntry.getRepoArtifactId();
474 
475         try {
476             Indexer.updateProductEntry(
477                 companyId, groupId, userId, userName, productEntryId, name,
478                 modifiedDate, version, type, shortDescription, longDescription,
479                 pageURL, repoGroupId, repoArtifactId);
480         }
481         catch (SearchException se) {
482             _log.error("Reindexing " + productEntry.getProductEntryId(), se);
483         }
484     }
485 
486     public void reIndex(String[] ids) throws SystemException {
487         if (SearchEngineUtil.isIndexReadOnly()) {
488             return;
489         }
490 
491         long companyId = GetterUtil.getLong(ids[0]);
492 
493         try {
494             reIndexProductEntries(companyId);
495         }
496         catch (SystemException se) {
497             throw se;
498         }
499         catch (Exception e) {
500             throw new SystemException(e);
501         }
502     }
503 
504     public Hits search(
505             long companyId, long groupId, String keywords, String type,
506             int start, int end)
507         throws SystemException {
508 
509         try {
510             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
511 
512             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
513             contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
514 
515             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
516 
517             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
518 
519             if (Validator.isNotNull(keywords)) {
520                 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
521 
522                 searchQuery.addTerm(Field.USER_NAME, keywords);
523                 searchQuery.addTerm(Field.TITLE, keywords);
524                 searchQuery.addTerm(Field.CONTENT, keywords);
525 
526                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
527             }
528 
529             if (Validator.isNotNull(type)) {
530                 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
531 
532                 searchQuery.addRequiredTerm("type", type);
533 
534                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
535             }
536 
537             return SearchEngineUtil.search(companyId, fullQuery, start, end);
538         }
539         catch (Exception e) {
540             throw new SystemException(e);
541         }
542     }
543 
544     public SCProductEntry updateProductEntry(
545             long productEntryId, String name, String type, String tags,
546             String shortDescription, String longDescription, String pageURL,
547             String author, String repoGroupId, String repoArtifactId,
548             long[] licenseIds, List<byte[]> thumbnails, List<byte[]> fullImages)
549         throws PortalException, SystemException {
550 
551         // Product entry
552 
553         tags = getTags(tags);
554         repoGroupId = repoGroupId.trim().toLowerCase();
555         repoArtifactId = repoArtifactId.trim().toLowerCase();
556         Date now = new Date();
557 
558         validate(
559             productEntryId, name, type, shortDescription, pageURL, author,
560             repoGroupId, repoArtifactId, licenseIds, thumbnails, fullImages);
561 
562         SCProductEntry productEntry =
563             scProductEntryPersistence.findByPrimaryKey(productEntryId);
564 
565         productEntry.setModifiedDate(now);
566         productEntry.setName(name);
567         productEntry.setType(type);
568         productEntry.setTags(tags);
569         productEntry.setShortDescription(shortDescription);
570         productEntry.setLongDescription(longDescription);
571         productEntry.setPageURL(pageURL);
572         productEntry.setAuthor(author);
573         productEntry.setRepoGroupId(repoGroupId);
574         productEntry.setRepoArtifactId(repoArtifactId);
575 
576         scProductEntryPersistence.update(productEntry, false);
577 
578         // Licenses
579 
580         scProductEntryPersistence.setSCLicenses(productEntryId, licenseIds);
581 
582         // Product screenshots
583 
584         if (thumbnails.size() == 0) {
585             scProductScreenshotLocalService.deleteProductScreenshots(
586                 productEntryId);
587         }
588         else {
589             saveProductScreenshots(productEntry, thumbnails, fullImages);
590         }
591 
592         // Indexer
593 
594         reIndex(productEntry);
595 
596         return productEntry;
597     }
598 
599     protected String getTags(String tags) {
600         tags = tags.trim().toLowerCase();
601 
602         return StringUtil.merge(StringUtil.split(tags), ", ");
603     }
604 
605     protected boolean isVersionSupported(
606         String version, List<SCFrameworkVersion> frameworkVersions) {
607 
608         Version currentVersion = Version.getInstance(version);
609 
610         for (SCFrameworkVersion frameworkVersion : frameworkVersions) {
611             Version supportedVersion = Version.getInstance(
612                 frameworkVersion.getName());
613 
614             if (supportedVersion.includes(currentVersion)) {
615                 return true;
616             }
617         }
618 
619         return false;
620     }
621 
622     protected void populatePluginPackageElement(
623             Element el, SCProductEntry productEntry,
624             SCProductVersion productVersion, String baseImageURL)
625         throws SystemException {
626 
627         DocUtil.add(el, "name", productEntry.getName());
628 
629         String moduleId = ModuleId.toString(
630             productEntry.getRepoGroupId(), productEntry.getRepoArtifactId(),
631             productVersion.getVersion(), "war");
632 
633         DocUtil.add(el, "module-id", moduleId);
634 
635         DocUtil.add(
636             el, "modified-date",
637             Time.getRFC822(productVersion.getModifiedDate()));
638 
639         Element typesEl = el.addElement("types");
640 
641         DocUtil.add(typesEl, "type", productEntry.getType());
642 
643         Element tagsEl = el.addElement("tags");
644 
645         String[] tags = StringUtil.split(productEntry.getTags());
646 
647         for (int i = 0; i < tags.length; i++) {
648             DocUtil.add(tagsEl, "tag", tags[i]);
649         }
650 
651         DocUtil.add(
652             el, "short-description", productEntry.getShortDescription());
653 
654         if (Validator.isNotNull(productEntry.getLongDescription())) {
655             DocUtil.add(
656                 el, "long-description", productEntry.getLongDescription());
657         }
658 
659         if (Validator.isNotNull(productVersion.getChangeLog())) {
660             DocUtil.add(el, "change-log", productVersion.getChangeLog());
661         }
662 
663         if (Validator.isNotNull(productVersion.getDirectDownloadURL())) {
664             DocUtil.add(
665                 el, "download-url", productVersion.getDirectDownloadURL());
666         }
667 
668         DocUtil.add(el, "author", productEntry.getAuthor());
669 
670         Element screenshotsEl = el.addElement("screenshots");
671 
672         for (SCProductScreenshot screenshot : productEntry.getScreenshots()) {
673             long thumbnailId = screenshot.getThumbnailId();
674             long fullImageId = screenshot.getFullImageId();
675 
676             Element screenshotEl = screenshotsEl.addElement("screenshot");
677 
678             DocUtil.add(
679                 screenshotEl, "thumbnail-url",
680                 baseImageURL + "?img_id=" + thumbnailId + "&t=" +
681                     ImageServletTokenUtil.getToken(thumbnailId));
682             DocUtil.add(
683                 screenshotEl, "large-image-url",
684                 baseImageURL + "?img_id=" + fullImageId + "&t=" +
685                     ImageServletTokenUtil.getToken(fullImageId));
686         }
687 
688         Element licensesEl = el.addElement("licenses");
689 
690         for (SCLicense license : productEntry.getLicenses()) {
691             Element licenseEl = licensesEl.addElement("license");
692 
693             licenseEl.addText(license.getName());
694             licenseEl.addAttribute(
695                 "osi-approved", String.valueOf(license.isOpenSource()));
696         }
697 
698         Element liferayVersionsEl = el.addElement("liferay-versions");
699 
700         for (SCFrameworkVersion frameworkVersion :
701                 productVersion.getFrameworkVersions()) {
702 
703             DocUtil.add(
704                 liferayVersionsEl, "liferay-version",
705                 frameworkVersion.getName());
706         }
707     }
708 
709     protected void populateSettingsElement(
710         Element el, Properties repoSettings) {
711 
712         if (repoSettings == null) {
713             return;
714         }
715 
716         Iterator<Object> itr = repoSettings.keySet().iterator();
717 
718         while (itr.hasNext()) {
719             String key = (String)itr.next();
720 
721             Element settingEl = el.addElement("setting");
722 
723             settingEl.addAttribute("name", key);
724             settingEl.addAttribute("value", repoSettings.getProperty(key));
725         }
726     }
727 
728     protected void reIndexProductEntries(long companyId)
729         throws SystemException {
730 
731         int count = scProductEntryPersistence.countByCompanyId(companyId);
732 
733         int pages = count / Indexer.DEFAULT_INTERVAL;
734 
735         for (int i = 0; i <= pages; i++) {
736             int start = (i * Indexer.DEFAULT_INTERVAL);
737             int end = start + Indexer.DEFAULT_INTERVAL;
738 
739             reIndexProductEntries(companyId, start, end);
740         }
741     }
742 
743     protected void reIndexProductEntries(long companyId, int start, int end)
744         throws SystemException {
745 
746         List<SCProductEntry> productEntries =
747             scProductEntryPersistence.findByCompanyId(companyId, start, end);
748 
749         for (SCProductEntry productEntry : productEntries) {
750             reIndex(productEntry);
751         }
752     }
753 
754     protected void saveProductScreenshots(
755             SCProductEntry productEntry, List<byte[]> thumbnails,
756             List<byte[]> fullImages)
757         throws PortalException, SystemException {
758 
759         long productEntryId = productEntry.getProductEntryId();
760 
761         List<SCProductScreenshot> productScreenshots =
762             scProductScreenshotPersistence.findByProductEntryId(productEntryId);
763 
764         if (thumbnails.size() < productScreenshots.size()) {
765             for (int i = thumbnails.size(); i < productScreenshots.size();
766                     i++) {
767 
768                 SCProductScreenshot productScreenshot =
769                     productScreenshots.get(i);
770 
771                 scProductScreenshotLocalService.deleteProductScreenshot(
772                     productScreenshot);
773             }
774         }
775 
776         for (int i = 0; i < thumbnails.size(); i++) {
777             int priority = i;
778 
779             byte[] thumbnail = thumbnails.get(i);
780             byte[] fullImage = fullImages.get(i);
781 
782             SCProductScreenshot productScreenshot =
783                 scProductScreenshotPersistence.fetchByP_P(
784                     productEntryId, priority);
785 
786             if (productScreenshot == null) {
787                 long productScreenshotId = counterLocalService.increment();
788 
789                 productScreenshot = scProductScreenshotPersistence.create(
790                     productScreenshotId);
791 
792                 productScreenshot.setCompanyId(productEntry.getCompanyId());
793                 productScreenshot.setGroupId(productEntry.getGroupId());
794                 productScreenshot.setProductEntryId(productEntryId);
795                 productScreenshot.setThumbnailId(
796                     counterLocalService.increment());
797                 productScreenshot.setFullImageId(
798                     counterLocalService.increment());
799                 productScreenshot.setPriority(priority);
800 
801                 scProductScreenshotPersistence.update(productScreenshot, false);
802             }
803 
804             imageLocalService.updateImage(
805                 productScreenshot.getThumbnailId(), thumbnail);
806             imageLocalService.updateImage(
807                 productScreenshot.getFullImageId(), fullImage);
808         }
809     }
810 
811     protected void validate(
812             long productEntryId, String name, String type,
813             String shortDescription, String pageURL, String author,
814             String repoGroupId, String repoArtifactId, long[] licenseIds,
815             List<byte[]> thumbnails, List<byte[]> fullImages)
816         throws PortalException, SystemException {
817 
818         if (Validator.isNull(name)) {
819             throw new ProductEntryNameException();
820         }
821 
822         if (Validator.isNull(type)) {
823             throw new ProductEntryTypeException();
824         }
825 
826         if (Validator.isNull(shortDescription)) {
827             throw new ProductEntryShortDescriptionException();
828         }
829 
830         if (Validator.isNull(pageURL)) {
831             throw new ProductEntryPageURLException();
832         }
833         else {
834             try {
835                 new URL(pageURL);
836             }
837             catch (MalformedURLException murle) {
838                 throw new ProductEntryPageURLException();
839             }
840         }
841 
842         if (Validator.isNull(author)) {
843             throw new ProductEntryAuthorException();
844         }
845 
846         SCProductEntry productEntry = scProductEntryPersistence.fetchByRG_RA(
847             repoGroupId, repoArtifactId);
848 
849         if ((productEntry != null) &&
850             (productEntry.getProductEntryId() != productEntryId)) {
851 
852             throw new DuplicateProductEntryModuleIdException();
853         }
854 
855         if (licenseIds.length == 0) {
856             throw new ProductEntryLicenseException();
857         }
858 
859         if (thumbnails.size() != fullImages.size()) {
860             throw new ProductEntryScreenshotsException();
861         }
862         else {
863             Iterator<byte[]> itr = thumbnails.iterator();
864 
865             while (itr.hasNext()) {
866                 if (itr.next() == null) {
867                     throw new ProductEntryScreenshotsException();
868                 }
869             }
870 
871             itr = fullImages.iterator();
872 
873             while (itr.hasNext()) {
874                 if (itr.next() == null) {
875                     throw new ProductEntryScreenshotsException();
876                 }
877             }
878         }
879     }
880 
881     private static Log _log =
882         LogFactoryUtil.getLog(SCProductEntryLocalServiceImpl.class);
883 
884 }