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