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