001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.softwarecatalog.service.impl;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.plugin.Version;
020    import com.liferay.portal.kernel.search.Indexable;
021    import com.liferay.portal.kernel.search.IndexableType;
022    import com.liferay.portal.kernel.util.OrderByComparator;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.kernel.util.StringUtil;
025    import com.liferay.portal.kernel.util.Time;
026    import com.liferay.portal.kernel.util.Validator;
027    import com.liferay.portal.kernel.workflow.WorkflowConstants;
028    import com.liferay.portal.kernel.xml.Document;
029    import com.liferay.portal.kernel.xml.Element;
030    import com.liferay.portal.kernel.xml.SAXReaderUtil;
031    import com.liferay.portal.model.ResourceConstants;
032    import com.liferay.portal.model.User;
033    import com.liferay.portal.plugin.ModuleId;
034    import com.liferay.portal.service.ServiceContext;
035    import com.liferay.portal.util.PropsValues;
036    import com.liferay.portal.webserver.WebServerServletTokenUtil;
037    import com.liferay.portlet.softwarecatalog.DuplicateProductEntryModuleIdException;
038    import com.liferay.portlet.softwarecatalog.ProductEntryAuthorException;
039    import com.liferay.portlet.softwarecatalog.ProductEntryLicenseException;
040    import com.liferay.portlet.softwarecatalog.ProductEntryNameException;
041    import com.liferay.portlet.softwarecatalog.ProductEntryPageURLException;
042    import com.liferay.portlet.softwarecatalog.ProductEntryScreenshotsException;
043    import com.liferay.portlet.softwarecatalog.ProductEntryShortDescriptionException;
044    import com.liferay.portlet.softwarecatalog.ProductEntryTypeException;
045    import com.liferay.portlet.softwarecatalog.model.SCFrameworkVersion;
046    import com.liferay.portlet.softwarecatalog.model.SCLicense;
047    import com.liferay.portlet.softwarecatalog.model.SCProductEntry;
048    import com.liferay.portlet.softwarecatalog.model.SCProductScreenshot;
049    import com.liferay.portlet.softwarecatalog.model.SCProductVersion;
050    import com.liferay.portlet.softwarecatalog.service.base.SCProductEntryLocalServiceBaseImpl;
051    import com.liferay.util.xml.DocUtil;
052    
053    import java.util.Date;
054    import java.util.List;
055    import java.util.Map;
056    import java.util.Properties;
057    
058    /**
059     * @author Jorge Ferrer
060     * @author Brian Wing Shun Chan
061     * @author Raymond Augé
062     */
063    public class SCProductEntryLocalServiceImpl
064            extends SCProductEntryLocalServiceBaseImpl {
065    
066            @Indexable(type = IndexableType.REINDEX)
067            public SCProductEntry addProductEntry(
068                            long userId, String name, String type, String tags,
069                            String shortDescription, String longDescription, String pageURL,
070                            String author, String repoGroupId, String repoArtifactId,
071                            long[] licenseIds, List<byte[]> thumbnails, List<byte[]> fullImages,
072                            ServiceContext serviceContext)
073                    throws PortalException, SystemException {
074    
075                    // Product entry
076    
077                    User user = userPersistence.findByPrimaryKey(userId);
078                    long groupId = serviceContext.getScopeGroupId();
079                    tags = getTags(tags);
080                    repoGroupId = repoGroupId.trim().toLowerCase();
081                    repoArtifactId = repoArtifactId.trim().toLowerCase();
082                    Date now = new Date();
083    
084                    validate(
085                            0, name, type, shortDescription, pageURL, author, repoGroupId,
086                            repoArtifactId, licenseIds, thumbnails, fullImages);
087    
088                    long productEntryId = counterLocalService.increment();
089    
090                    SCProductEntry productEntry = scProductEntryPersistence.create(
091                            productEntryId);
092    
093                    productEntry.setGroupId(groupId);
094                    productEntry.setCompanyId(user.getCompanyId());
095                    productEntry.setUserId(user.getUserId());
096                    productEntry.setUserName(user.getFullName());
097                    productEntry.setCreateDate(now);
098                    productEntry.setModifiedDate(now);
099                    productEntry.setName(name);
100                    productEntry.setType(type);
101                    productEntry.setTags(tags);
102                    productEntry.setShortDescription(shortDescription);
103                    productEntry.setLongDescription(longDescription);
104                    productEntry.setPageURL(pageURL);
105                    productEntry.setAuthor(author);
106                    productEntry.setRepoGroupId(repoGroupId);
107                    productEntry.setRepoArtifactId(repoArtifactId);
108    
109                    scProductEntryPersistence.update(productEntry);
110    
111                    // Resources
112    
113                    if (serviceContext.isAddGroupPermissions() ||
114                            serviceContext.isAddGuestPermissions()) {
115    
116                            addProductEntryResources(
117                                    productEntry, serviceContext.isAddGroupPermissions(),
118                                    serviceContext.isAddGuestPermissions());
119                    }
120                    else {
121                            addProductEntryResources(
122                                    productEntry, serviceContext.getGroupPermissions(),
123                                    serviceContext.getGuestPermissions());
124                    }
125    
126                    // Licenses
127    
128                    scProductEntryPersistence.setSCLicenses(productEntryId, licenseIds);
129    
130                    // Product screenshots
131    
132                    saveProductScreenshots(productEntry, thumbnails, fullImages);
133    
134                    // Message boards
135    
136                    if (PropsValues.SC_PRODUCT_COMMENTS_ENABLED) {
137                            mbMessageLocalService.addDiscussionMessage(
138                                    userId, productEntry.getUserName(), groupId,
139                                    SCProductEntry.class.getName(), productEntryId,
140                                    WorkflowConstants.ACTION_PUBLISH);
141                    }
142    
143                    return productEntry;
144            }
145    
146            public void addProductEntryResources(
147                            long productEntryId, boolean addGroupPermissions,
148                            boolean addGuestPermissions)
149                    throws PortalException, SystemException {
150    
151                    SCProductEntry productEntry =
152                            scProductEntryPersistence.findByPrimaryKey(productEntryId);
153    
154                    addProductEntryResources(
155                            productEntry, addGroupPermissions, addGuestPermissions);
156            }
157    
158            public void addProductEntryResources(
159                            long productEntryId, String[] groupPermissions,
160                            String[] guestPermissions)
161                    throws PortalException, SystemException {
162    
163                    SCProductEntry productEntry =
164                            scProductEntryPersistence.findByPrimaryKey(productEntryId);
165    
166                    addProductEntryResources(
167                            productEntry, groupPermissions, guestPermissions);
168            }
169    
170            public void addProductEntryResources(
171                            SCProductEntry productEntry, boolean addGroupPermissions,
172                            boolean addGuestPermissions)
173                    throws PortalException, SystemException {
174    
175                    resourceLocalService.addResources(
176                            productEntry.getCompanyId(), productEntry.getGroupId(),
177                            productEntry.getUserId(), SCProductEntry.class.getName(),
178                            productEntry.getProductEntryId(), false, addGroupPermissions,
179                            addGuestPermissions);
180            }
181    
182            public void addProductEntryResources(
183                            SCProductEntry productEntry, String[] groupPermissions,
184                            String[] guestPermissions)
185                    throws PortalException, SystemException {
186    
187                    resourceLocalService.addModelResources(
188                            productEntry.getCompanyId(), productEntry.getGroupId(),
189                            productEntry.getUserId(), SCProductEntry.class.getName(),
190                            productEntry.getProductEntryId(), groupPermissions,
191                            guestPermissions);
192            }
193    
194            public void deleteProductEntries(long groupId)
195                    throws PortalException, SystemException {
196    
197                    List<SCProductEntry> productEntries =
198                            scProductEntryPersistence.findByGroupId(groupId);
199    
200                    for (SCProductEntry productEntry : productEntries) {
201                            scProductEntryLocalService.deleteProductEntry(productEntry);
202                    }
203            }
204    
205            @Indexable(type = IndexableType.DELETE)
206            public SCProductEntry deleteProductEntry(long productEntryId)
207                    throws PortalException, SystemException {
208    
209                    SCProductEntry productEntry =
210                            scProductEntryPersistence.findByPrimaryKey(productEntryId);
211    
212                    return deleteProductEntry(productEntry);
213            }
214    
215            @Indexable(type = IndexableType.DELETE)
216            public SCProductEntry deleteProductEntry(SCProductEntry productEntry)
217                    throws PortalException, SystemException {
218    
219                    // Product entry
220    
221                    scProductEntryPersistence.remove(productEntry);
222    
223                    // Resources
224    
225                    resourceLocalService.deleteResource(
226                            productEntry.getCompanyId(), SCProductEntry.class.getName(),
227                            ResourceConstants.SCOPE_INDIVIDUAL,
228                            productEntry.getProductEntryId());
229    
230                    // Subscriptions
231    
232                    subscriptionLocalService.deleteSubscriptions(
233                            productEntry.getCompanyId(), SCProductEntry.class.getName(),
234                            productEntry.getProductEntryId());
235    
236                    // Product screenshots
237    
238                    scProductScreenshotLocalService.deleteProductScreenshots(
239                            productEntry.getProductEntryId());
240    
241                    // Product versions
242    
243                    scProductVersionLocalService.deleteProductVersions(
244                            productEntry.getProductEntryId());
245    
246                    // Message boards
247    
248                    mbMessageLocalService.deleteDiscussionMessages(
249                            SCProductEntry.class.getName(), productEntry.getProductEntryId());
250    
251                    // Ratings
252    
253                    ratingsStatsLocalService.deleteStats(
254                            SCProductEntry.class.getName(), productEntry.getProductEntryId());
255    
256                    return productEntry;
257            }
258    
259            public List<SCProductEntry> getCompanyProductEntries(
260                            long companyId, int start, int end)
261                    throws SystemException {
262    
263                    return scProductEntryPersistence.findByCompanyId(companyId, start, end);
264            }
265    
266            public int getCompanyProductEntriesCount(long companyId)
267                    throws SystemException {
268    
269                    return scProductEntryPersistence.countByCompanyId(companyId);
270            }
271    
272            public List<SCProductEntry> getProductEntries(
273                            long groupId, int start, int end)
274                    throws SystemException {
275    
276                    return scProductEntryPersistence.findByGroupId(groupId, start, end);
277            }
278    
279            public List<SCProductEntry> getProductEntries(
280                            long groupId, int start, int end, OrderByComparator obc)
281                    throws SystemException {
282    
283                    return scProductEntryPersistence.findByGroupId(
284                            groupId, start, end, obc);
285            }
286    
287            public List<SCProductEntry> getProductEntries(
288                            long groupId, long userId, int start, int end)
289                    throws SystemException {
290    
291                    return scProductEntryPersistence.findByG_U(groupId, userId, start, end);
292            }
293    
294            public List<SCProductEntry> getProductEntries(
295                            long groupId, long userId, int start, int end,
296                            OrderByComparator obc)
297                    throws SystemException {
298    
299                    return scProductEntryPersistence.findByG_U(
300                            groupId, userId, start, end, obc);
301            }
302    
303            public int getProductEntriesCount(long groupId) throws SystemException {
304                    return scProductEntryPersistence.countByGroupId(groupId);
305            }
306    
307            public int getProductEntriesCount(long groupId, long userId)
308                    throws SystemException {
309    
310                    return scProductEntryPersistence.countByG_U(groupId, userId);
311            }
312    
313            public SCProductEntry getProductEntry(long productEntryId)
314                    throws PortalException, SystemException {
315    
316                    return scProductEntryPersistence.findByPrimaryKey(productEntryId);
317            }
318    
319            public String getRepositoryXML(
320                            long groupId, String baseImageURL, Date oldestDate,
321                            int maxNumOfVersions, Properties repoSettings)
322                    throws SystemException {
323    
324                    return getRepositoryXML(
325                            groupId, null, baseImageURL, oldestDate, maxNumOfVersions,
326                            repoSettings);
327            }
328    
329            public String getRepositoryXML(
330                            long groupId, String version, String baseImageURL, Date oldestDate,
331                            int maxNumOfVersions, Properties repoSettings)
332                    throws SystemException {
333    
334                    Document doc = SAXReaderUtil.createDocument();
335    
336                    doc.setXMLEncoding(StringPool.UTF8);
337    
338                    Element root = doc.addElement("plugin-repository");
339    
340                    Element settingsEl = root.addElement("settings");
341    
342                    populateSettingsElement(settingsEl, repoSettings);
343    
344                    List<SCProductEntry> productEntries =
345                            scProductEntryPersistence.findByGroupId(groupId);
346    
347                    for (SCProductEntry productEntry : productEntries) {
348                            if (Validator.isNull(productEntry.getRepoGroupId()) ||
349                                    Validator.isNull(productEntry.getRepoArtifactId())) {
350    
351                                    continue;
352                            }
353    
354                            List<SCProductVersion> productVersions =
355                                    scProductVersionPersistence.findByProductEntryId(
356                                            productEntry.getProductEntryId());
357    
358                            for (int i = 0; i < productVersions.size(); i++) {
359                                    SCProductVersion productVersion = productVersions.get(i);
360    
361                                    if ((maxNumOfVersions > 0) && (maxNumOfVersions < (i + 1))) {
362                                            break;
363                                    }
364    
365                                    if (!productVersion.isRepoStoreArtifact()) {
366                                            continue;
367                                    }
368    
369                                    if ((oldestDate != null) &&
370                                            oldestDate.after(productVersion.getModifiedDate())) {
371    
372                                            continue;
373                                    }
374    
375                                    if (Validator.isNotNull(version) &&
376                                            !isVersionSupported(
377                                                    version, productVersion.getFrameworkVersions())) {
378    
379                                            continue;
380                                    }
381    
382                                    Element el = root.addElement("plugin-package");
383    
384                                    populatePluginPackageElement(
385                                            el, productEntry, productVersion, baseImageURL);
386                            }
387                    }
388    
389                    return doc.asXML();
390            }
391    
392            @Indexable(type = IndexableType.REINDEX)
393            public SCProductEntry updateProductEntry(
394                            long productEntryId, String name, String type, String tags,
395                            String shortDescription, String longDescription, String pageURL,
396                            String author, String repoGroupId, String repoArtifactId,
397                            long[] licenseIds, List<byte[]> thumbnails, List<byte[]> fullImages)
398                    throws PortalException, SystemException {
399    
400                    // Product entry
401    
402                    tags = getTags(tags);
403                    repoGroupId = repoGroupId.trim().toLowerCase();
404                    repoArtifactId = repoArtifactId.trim().toLowerCase();
405                    Date now = new Date();
406    
407                    validate(
408                            productEntryId, name, type, shortDescription, pageURL, author,
409                            repoGroupId, repoArtifactId, licenseIds, thumbnails, fullImages);
410    
411                    SCProductEntry productEntry =
412                            scProductEntryPersistence.findByPrimaryKey(productEntryId);
413    
414                    productEntry.setModifiedDate(now);
415                    productEntry.setName(name);
416                    productEntry.setType(type);
417                    productEntry.setTags(tags);
418                    productEntry.setShortDescription(shortDescription);
419                    productEntry.setLongDescription(longDescription);
420                    productEntry.setPageURL(pageURL);
421                    productEntry.setAuthor(author);
422                    productEntry.setRepoGroupId(repoGroupId);
423                    productEntry.setRepoArtifactId(repoArtifactId);
424    
425                    scProductEntryPersistence.update(productEntry);
426    
427                    // Licenses
428    
429                    scProductEntryPersistence.setSCLicenses(productEntryId, licenseIds);
430    
431                    // Product screenshots
432    
433                    if (thumbnails.size() == 0) {
434                            scProductScreenshotLocalService.deleteProductScreenshots(
435                                    productEntryId);
436                    }
437                    else {
438                            saveProductScreenshots(productEntry, thumbnails, fullImages);
439                    }
440    
441                    return productEntry;
442            }
443    
444            protected String getTags(String tags) {
445                    tags = tags.trim().toLowerCase();
446    
447                    return StringUtil.merge(StringUtil.split(tags), ", ");
448            }
449    
450            protected boolean isVersionSupported(
451                    String version, List<SCFrameworkVersion> frameworkVersions) {
452    
453                    Version currentVersion = Version.getInstance(version);
454    
455                    for (SCFrameworkVersion frameworkVersion : frameworkVersions) {
456                            Version supportedVersion = Version.getInstance(
457                                    frameworkVersion.getName());
458    
459                            if (supportedVersion.includes(currentVersion)) {
460                                    return true;
461                            }
462                    }
463    
464                    return false;
465            }
466    
467            protected void populatePluginPackageElement(
468                            Element el, SCProductEntry productEntry,
469                            SCProductVersion productVersion, String baseImageURL)
470                    throws SystemException {
471    
472                    DocUtil.add(el, "name", productEntry.getName());
473    
474                    String moduleId = ModuleId.toString(
475                            productEntry.getRepoGroupId(), productEntry.getRepoArtifactId(),
476                            productVersion.getVersion(), "war");
477    
478                    DocUtil.add(el, "module-id", moduleId);
479    
480                    DocUtil.add(
481                            el, "modified-date",
482                            Time.getRFC822(productVersion.getModifiedDate()));
483    
484                    Element typesEl = el.addElement("types");
485    
486                    DocUtil.add(typesEl, "type", productEntry.getType());
487    
488                    Element tagsEl = el.addElement("tags");
489    
490                    String[] tags = StringUtil.split(productEntry.getTags());
491    
492                    for (int i = 0; i < tags.length; i++) {
493                            DocUtil.add(tagsEl, "tag", tags[i]);
494                    }
495    
496                    DocUtil.add(
497                            el, "short-description", productEntry.getShortDescription());
498    
499                    if (Validator.isNotNull(productEntry.getLongDescription())) {
500                            DocUtil.add(
501                                    el, "long-description", productEntry.getLongDescription());
502                    }
503    
504                    if (Validator.isNotNull(productVersion.getChangeLog())) {
505                            DocUtil.add(el, "change-log", productVersion.getChangeLog());
506                    }
507    
508                    if (Validator.isNotNull(productVersion.getDirectDownloadURL())) {
509                            DocUtil.add(
510                                    el, "download-url", productVersion.getDirectDownloadURL());
511                    }
512    
513                    DocUtil.add(el, "author", productEntry.getAuthor());
514    
515                    Element screenshotsEl = el.addElement("screenshots");
516    
517                    for (SCProductScreenshot screenshot : productEntry.getScreenshots()) {
518                            long thumbnailId = screenshot.getThumbnailId();
519                            long fullImageId = screenshot.getFullImageId();
520    
521                            Element screenshotEl = screenshotsEl.addElement("screenshot");
522    
523                            DocUtil.add(
524                                    screenshotEl, "thumbnail-url",
525                                    baseImageURL + "?img_id=" + thumbnailId + "&t=" +
526                                            WebServerServletTokenUtil.getToken(thumbnailId));
527                            DocUtil.add(
528                                    screenshotEl, "large-image-url",
529                                    baseImageURL + "?img_id=" + fullImageId + "&t=" +
530                                            WebServerServletTokenUtil.getToken(fullImageId));
531                    }
532    
533                    Element licensesEl = el.addElement("licenses");
534    
535                    for (SCLicense license : productEntry.getLicenses()) {
536                            Element licenseEl = licensesEl.addElement("license");
537    
538                            licenseEl.addText(license.getName());
539                            licenseEl.addAttribute(
540                                    "osi-approved", String.valueOf(license.isOpenSource()));
541                    }
542    
543                    Element liferayVersionsEl = el.addElement("liferay-versions");
544    
545                    for (SCFrameworkVersion frameworkVersion :
546                                    productVersion.getFrameworkVersions()) {
547    
548                            DocUtil.add(
549                                    liferayVersionsEl, "liferay-version",
550                                    frameworkVersion.getName());
551                    }
552            }
553    
554            protected void populateSettingsElement(
555                    Element el, Properties repoSettings) {
556    
557                    if (repoSettings == null) {
558                            return;
559                    }
560    
561                    for (Map.Entry<Object, Object> entry : repoSettings.entrySet()) {
562                            String name = (String)entry.getKey();
563                            String value = (String)entry.getValue();
564    
565                            Element settingEl = el.addElement("setting");
566    
567                            settingEl.addAttribute("name", name);
568                            settingEl.addAttribute("value", value);
569                    }
570            }
571    
572            protected void saveProductScreenshots(
573                            SCProductEntry productEntry, List<byte[]> thumbnails,
574                            List<byte[]> fullImages)
575                    throws PortalException, SystemException {
576    
577                    long productEntryId = productEntry.getProductEntryId();
578    
579                    List<SCProductScreenshot> productScreenshots =
580                            scProductScreenshotPersistence.findByProductEntryId(productEntryId);
581    
582                    if (thumbnails.size() < productScreenshots.size()) {
583                            for (int i = thumbnails.size(); i < productScreenshots.size();
584                                            i++) {
585    
586                                    SCProductScreenshot productScreenshot = productScreenshots.get(
587                                            i);
588    
589                                    scProductScreenshotLocalService.deleteProductScreenshot(
590                                            productScreenshot);
591                            }
592                    }
593    
594                    for (int i = 0; i < thumbnails.size(); i++) {
595                            int priority = i;
596    
597                            byte[] thumbnail = thumbnails.get(i);
598                            byte[] fullImage = fullImages.get(i);
599    
600                            SCProductScreenshot productScreenshot =
601                                    scProductScreenshotPersistence.fetchByP_P(
602                                            productEntryId, priority);
603    
604                            if (productScreenshot == null) {
605                                    long productScreenshotId = counterLocalService.increment();
606    
607                                    productScreenshot = scProductScreenshotPersistence.create(
608                                            productScreenshotId);
609    
610                                    productScreenshot.setCompanyId(productEntry.getCompanyId());
611                                    productScreenshot.setGroupId(productEntry.getGroupId());
612                                    productScreenshot.setProductEntryId(productEntryId);
613                                    productScreenshot.setThumbnailId(
614                                            counterLocalService.increment());
615                                    productScreenshot.setFullImageId(
616                                            counterLocalService.increment());
617                                    productScreenshot.setPriority(priority);
618    
619                                    scProductScreenshotPersistence.update(productScreenshot);
620                            }
621    
622                            imageLocalService.updateImage(
623                                    productScreenshot.getThumbnailId(), thumbnail);
624                            imageLocalService.updateImage(
625                                    productScreenshot.getFullImageId(), fullImage);
626                    }
627            }
628    
629            protected void validate(
630                            long productEntryId, String name, String type,
631                            String shortDescription, String pageURL, String author,
632                            String repoGroupId, String repoArtifactId, long[] licenseIds,
633                            List<byte[]> thumbnails, List<byte[]> fullImages)
634                    throws PortalException, SystemException {
635    
636                    if (Validator.isNull(name)) {
637                            throw new ProductEntryNameException();
638                    }
639    
640                    if (Validator.isNull(type)) {
641                            throw new ProductEntryTypeException();
642                    }
643    
644                    if (Validator.isNull(shortDescription)) {
645                            throw new ProductEntryShortDescriptionException();
646                    }
647    
648                    if (Validator.isNull(pageURL)) {
649                            throw new ProductEntryPageURLException();
650                    }
651                    else if (!Validator.isUrl(pageURL)) {
652                            throw new ProductEntryPageURLException();
653                    }
654    
655                    if (Validator.isNull(author)) {
656                            throw new ProductEntryAuthorException();
657                    }
658    
659                    SCProductEntry productEntry = scProductEntryPersistence.fetchByRG_RA(
660                            repoGroupId, repoArtifactId);
661    
662                    if ((productEntry != null) &&
663                            (productEntry.getProductEntryId() != productEntryId)) {
664    
665                            throw new DuplicateProductEntryModuleIdException();
666                    }
667    
668                    if (licenseIds.length == 0) {
669                            throw new ProductEntryLicenseException();
670                    }
671    
672                    if (thumbnails.size() != fullImages.size()) {
673                            throw new ProductEntryScreenshotsException();
674                    }
675                    else {
676                            for (byte[] thumbnail : thumbnails) {
677                                    if (thumbnail == null) {
678                                            throw new ProductEntryScreenshotsException();
679                                    }
680                            }
681    
682                            for (byte[] fullImage : fullImages) {
683                                    if (fullImage == null) {
684                                            throw new ProductEntryScreenshotsException();
685                                    }
686                            }
687                    }
688            }
689    
690    }