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.imagegallery.service.impl;
24  
25  import com.liferay.portal.PortalException;
26  import com.liferay.portal.SystemException;
27  import com.liferay.portal.kernel.image.ImageProcessor;
28  import com.liferay.portal.kernel.image.ImageProcessorUtil;
29  import com.liferay.portal.kernel.search.SearchException;
30  import com.liferay.portal.kernel.util.ByteArrayMaker;
31  import com.liferay.portal.kernel.util.FileUtil;
32  import com.liferay.portal.kernel.util.GetterUtil;
33  import com.liferay.portal.kernel.util.OrderByComparator;
34  import com.liferay.portal.kernel.util.StringPool;
35  import com.liferay.portal.kernel.util.StringUtil;
36  import com.liferay.portal.kernel.util.Validator;
37  import com.liferay.portal.model.Image;
38  import com.liferay.portal.model.ResourceConstants;
39  import com.liferay.portal.model.User;
40  import com.liferay.portal.util.PropsKeys;
41  import com.liferay.portal.util.PropsUtil;
42  import com.liferay.portal.util.PropsValues;
43  import com.liferay.portlet.imagegallery.DuplicateImageNameException;
44  import com.liferay.portlet.imagegallery.ImageNameException;
45  import com.liferay.portlet.imagegallery.ImageSizeException;
46  import com.liferay.portlet.imagegallery.NoSuchImageException;
47  import com.liferay.portlet.imagegallery.model.IGFolder;
48  import com.liferay.portlet.imagegallery.model.IGImage;
49  import com.liferay.portlet.imagegallery.model.impl.IGImageImpl;
50  import com.liferay.portlet.imagegallery.service.base.IGImageLocalServiceBaseImpl;
51  import com.liferay.portlet.imagegallery.util.Indexer;
52  
53  import com.sun.media.jai.codec.ImageCodec;
54  import com.sun.media.jai.codec.ImageEncoder;
55  
56  import java.awt.image.RenderedImage;
57  
58  import java.io.File;
59  import java.io.IOException;
60  
61  import java.util.Date;
62  import java.util.List;
63  
64  import javax.imageio.ImageIO;
65  
66  import org.apache.commons.logging.Log;
67  import org.apache.commons.logging.LogFactory;
68  
69  /**
70   * <a href="IGImageLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
71   *
72   * @author Brian Wing Shun Chan
73   *
74   */
75  public class IGImageLocalServiceImpl extends IGImageLocalServiceBaseImpl {
76  
77      public IGImage addImage(
78              long userId, long folderId, String name, String description,
79              File file, String contentType, String[] tagsEntries,
80              boolean addCommunityPermissions, boolean addGuestPermissions)
81          throws PortalException, SystemException {
82  
83          return addImage(
84              null, userId, folderId, name, description, file, contentType,
85              tagsEntries, Boolean.valueOf(addCommunityPermissions),
86              Boolean.valueOf(addGuestPermissions), null, null);
87      }
88  
89      public IGImage addImage(
90              String uuid, long userId, long folderId, String name,
91              String description, File file, String contentType,
92              String[] tagsEntries, boolean addCommunityPermissions,
93              boolean addGuestPermissions)
94          throws PortalException, SystemException {
95  
96          return addImage(
97              uuid, userId, folderId, name, description, file, contentType,
98              tagsEntries, Boolean.valueOf(addCommunityPermissions),
99              Boolean.valueOf(addGuestPermissions), null, null);
100     }
101 
102     public IGImage addImage(
103             long userId, long folderId, String name, String description,
104             File file, String contentType, String[] tagsEntries,
105             String[] communityPermissions, String[] guestPermissions)
106         throws PortalException, SystemException {
107 
108         return addImage(
109             null, userId, folderId, name, description, file, contentType,
110             tagsEntries, null, null, communityPermissions, guestPermissions);
111     }
112 
113     public IGImage addImage(
114             String uuid, long userId, long folderId, String name,
115             String description, File file, String contentType,
116             String[] tagsEntries, Boolean addCommunityPermissions,
117             Boolean addGuestPermissions, String[] communityPermissions,
118             String[] guestPermissions)
119         throws PortalException, SystemException {
120 
121         try {
122 
123             // Image
124 
125             String extension = FileUtil.getExtension(file.getName());
126 
127             if (Validator.isNotNull(name) &&
128                 StringUtil.endsWith(name, extension)) {
129 
130                 name = FileUtil.stripExtension(name);
131             }
132 
133             String nameWithExtension = name + StringPool.PERIOD + extension;
134             byte[] bytes = FileUtil.getBytes(file);
135 
136             validate(folderId, nameWithExtension, file, bytes);
137 
138             User user = userPersistence.findByPrimaryKey(userId);
139             IGFolder folder = igFolderPersistence.findByPrimaryKey(folderId);
140             RenderedImage renderedImage = ImageProcessorUtil.read(
141                 file).getRenderedImage();
142             Date now = new Date();
143 
144             long imageId = counterLocalService.increment();
145 
146             if (Validator.isNull(name)) {
147                 name = String.valueOf(imageId);
148             }
149 
150             IGImage image = igImagePersistence.create(imageId);
151 
152             image.setUuid(uuid);
153             image.setCompanyId(user.getCompanyId());
154             image.setUserId(user.getUserId());
155             image.setCreateDate(now);
156             image.setModifiedDate(now);
157             image.setFolderId(folderId);
158             image.setName(name);
159             image.setDescription(description);
160             image.setSmallImageId(counterLocalService.increment());
161             image.setLargeImageId(counterLocalService.increment());
162 
163             if (PropsValues.IG_IMAGE_CUSTOM_1_MAX_DIMENSION > 0) {
164                 image.setCustom1ImageId(counterLocalService.increment());
165             }
166 
167             if (PropsValues.IG_IMAGE_CUSTOM_2_MAX_DIMENSION > 0) {
168                 image.setCustom2ImageId(counterLocalService.increment());
169             }
170 
171             igImagePersistence.update(image, false);
172 
173             // Images
174 
175             saveImages(
176                 image.getLargeImageId(), renderedImage, image.getSmallImageId(),
177                 image.getCustom1ImageId(), image.getCustom2ImageId(), file,
178                 bytes, contentType);
179 
180             // Resources
181 
182             if ((addCommunityPermissions != null) &&
183                 (addGuestPermissions != null)) {
184 
185                 addImageResources(
186                     folder, image, addCommunityPermissions.booleanValue(),
187                     addGuestPermissions.booleanValue());
188             }
189             else {
190                 addImageResources(
191                     folder, image, communityPermissions, guestPermissions);
192             }
193 
194             // Tags
195 
196             updateTagsAsset(userId, image, tagsEntries);
197 
198             // Lucene
199 
200             try {
201                 Indexer.addImage(
202                     image.getCompanyId(), folder.getGroupId(), folderId,
203                     imageId, name, description, tagsEntries);
204             }
205             catch (SearchException se) {
206                 _log.error("Indexing " + imageId, se);
207             }
208 
209             return image;
210         }
211         catch (IOException ioe) {
212             throw new ImageSizeException(ioe);
213         }
214     }
215 
216     public void addImageResources(
217             long folderId, long imageId, boolean addCommunityPermissions,
218             boolean addGuestPermissions)
219         throws PortalException, SystemException {
220 
221         IGFolder folder = igFolderPersistence.findByPrimaryKey(folderId);
222         IGImage image = igImagePersistence.findByPrimaryKey(imageId);
223 
224         addImageResources(
225             folder, image, addCommunityPermissions, addGuestPermissions);
226     }
227 
228     public void addImageResources(
229             IGFolder folder, IGImage image, boolean addCommunityPermissions,
230             boolean addGuestPermissions)
231         throws PortalException, SystemException {
232 
233         resourceLocalService.addResources(
234             image.getCompanyId(), folder.getGroupId(), image.getUserId(),
235             IGImage.class.getName(), image.getImageId(), false,
236             addCommunityPermissions, addGuestPermissions);
237     }
238 
239     public void addImageResources(
240             long folderId, long imageId, String[] communityPermissions,
241             String[] guestPermissions)
242         throws PortalException, SystemException {
243 
244         IGFolder folder = igFolderPersistence.findByPrimaryKey(folderId);
245         IGImage image = igImagePersistence.findByPrimaryKey(imageId);
246 
247         addImageResources(
248             folder, image, communityPermissions, guestPermissions);
249     }
250 
251     public void addImageResources(
252             IGFolder folder, IGImage image, String[] communityPermissions,
253             String[] guestPermissions)
254         throws PortalException, SystemException {
255 
256         resourceLocalService.addModelResources(
257             image.getCompanyId(), folder.getGroupId(), image.getUserId(),
258             IGImage.class.getName(), image.getImageId(), communityPermissions,
259             guestPermissions);
260     }
261 
262     public void deleteImage(long imageId)
263         throws PortalException, SystemException {
264 
265         IGImage image = igImagePersistence.findByPrimaryKey(imageId);
266 
267         deleteImage(image);
268     }
269 
270     public void deleteImage(IGImage image)
271         throws PortalException, SystemException {
272 
273         // Lucene
274 
275         try {
276             Indexer.deleteImage(image.getCompanyId(), image.getImageId());
277         }
278         catch (SearchException se) {
279             _log.error("Deleting index " + image.getImageId(), se);
280         }
281 
282         // Tags
283 
284         tagsAssetLocalService.deleteAsset(
285             IGImage.class.getName(), image.getImageId());
286 
287         // Resources
288 
289         resourceLocalService.deleteResource(
290             image.getCompanyId(), IGImage.class.getName(),
291             ResourceConstants.SCOPE_INDIVIDUAL, image.getImageId());
292 
293         // Images
294 
295         imageLocalService.deleteImage(image.getSmallImageId());
296         imageLocalService.deleteImage(image.getLargeImageId());
297 
298         // Image
299 
300         igImagePersistence.remove(image.getPrimaryKey());
301     }
302 
303     public void deleteImages(long folderId)
304         throws PortalException, SystemException {
305 
306         List<IGImage> images = igImagePersistence.findByFolderId(folderId);
307 
308         for (IGImage image : images) {
309             deleteImage(image);
310         }
311     }
312 
313     public int getFoldersImagesCount(List<Long> folderIds)
314         throws SystemException {
315 
316         return igImageFinder.countByFolderIds(folderIds);
317     }
318 
319     public List<IGImage> getGroupImages(long groupId, int start, int end)
320         throws SystemException {
321 
322         return igImageFinder.findByGroupId(groupId, start, end);
323     }
324 
325     public List<IGImage> getGroupImages(
326             long groupId, long userId, int start, int end)
327         throws SystemException {
328 
329         if (userId <= 0) {
330             return igImageFinder.findByGroupId(groupId, start, end);
331         }
332         else {
333             return igImageFinder.findByG_U(groupId, userId, start, end);
334         }
335     }
336 
337     public int getGroupImagesCount(long groupId) throws SystemException {
338         return igImageFinder.countByGroupId(groupId);
339     }
340 
341     public int getGroupImagesCount(long groupId, long userId)
342         throws SystemException {
343 
344         if (userId <= 0) {
345             return igImageFinder.countByGroupId(groupId);
346         }
347         else {
348             return igImageFinder.countByG_U(groupId, userId);
349         }
350     }
351 
352     public IGImage getImage(long imageId)
353         throws PortalException, SystemException {
354 
355         return igImagePersistence.findByPrimaryKey(imageId);
356     }
357 
358     public IGImage getImageByCustom1ImageId(long custom1ImageId)
359         throws PortalException, SystemException {
360 
361         return igImagePersistence.findByCustom1ImageId(custom1ImageId);
362     }
363 
364     public IGImage getImageByCustom2ImageId(long custom2ImageId)
365         throws PortalException, SystemException {
366 
367         return igImagePersistence.findByCustom2ImageId(custom2ImageId);
368     }
369 
370     public IGImage getImageByFolderIdAndNameWithExtension(
371             long folderId, String nameWithExtension)
372         throws PortalException, SystemException {
373 
374         String name = FileUtil.stripExtension(nameWithExtension);
375 
376         List<IGImage> images = igImagePersistence.findByF_N(folderId, name);
377 
378         if ((images.size() <= 0) && Validator.isNumber(name)) {
379             long imageId = GetterUtil.getLong(name);
380 
381             IGImage image = igImagePersistence.fetchByPrimaryKey(imageId);
382 
383             if (image != null) {
384                 images.add(image);
385             }
386         }
387 
388         for (IGImage image : images) {
389             if (nameWithExtension.equals(image.getNameWithExtension())) {
390                 return image;
391             }
392         }
393 
394         throw new NoSuchImageException();
395     }
396 
397     public IGImage getImageByLargeImageId(long largeImageId)
398         throws PortalException, SystemException {
399 
400         return igImagePersistence.findByLargeImageId(largeImageId);
401     }
402 
403     public IGImage getImageBySmallImageId(long smallImageId)
404         throws PortalException, SystemException {
405 
406         return igImagePersistence.findBySmallImageId(smallImageId);
407     }
408 
409     public IGImage getImageByUuidAndGroupId(String uuid, long groupId)
410         throws PortalException, SystemException {
411 
412         return igImageFinder.findByUuid_G(uuid, groupId);
413     }
414 
415     public List<IGImage> getImages(long folderId) throws SystemException {
416         return igImagePersistence.findByFolderId(folderId);
417     }
418 
419     public List<IGImage> getImages(long folderId, int start, int end)
420         throws SystemException {
421 
422         return igImagePersistence.findByFolderId(folderId, start, end);
423     }
424 
425     public List<IGImage> getImages(
426             long folderId, int start, int end, OrderByComparator obc)
427         throws SystemException {
428 
429         return igImagePersistence.findByFolderId(folderId, start, end, obc);
430     }
431 
432     public int getImagesCount(long folderId) throws SystemException {
433         return igImagePersistence.countByFolderId(folderId);
434     }
435 
436     public List<IGImage> getNoAssetImages() throws SystemException {
437         return igImageFinder.findByNoAssets();
438     }
439 
440     public IGImage updateImage(
441             long userId, long imageId, long folderId, String name,
442             String description, File file, String contentType,
443             String[] tagsEntries)
444         throws PortalException, SystemException {
445 
446         try {
447 
448             // Image
449 
450             IGImage image = igImagePersistence.findByPrimaryKey(imageId);
451 
452             IGFolder folder = getFolder(image, folderId);
453 
454             RenderedImage renderedImage = null;
455             byte[] bytes = null;
456 
457             if ((file != null) && file.exists()) {
458                 renderedImage = ImageProcessorUtil.read(
459                     file).getRenderedImage();
460                 bytes = FileUtil.getBytes(file);
461 
462                 validate(bytes);
463             }
464 
465             if (Validator.isNotNull(name) && !name.equals(image.getName())) {
466                 String nameWithExtension = IGImageImpl.getNameWithExtension(
467                     name, image.getImageType());
468 
469                 validate(folderId, nameWithExtension);
470             }
471             else {
472                 name = image.getName();
473             }
474 
475             image.setModifiedDate(new Date());
476             image.setFolderId(folder.getFolderId());
477             image.setName(name);
478             image.setDescription(description);
479 
480             igImagePersistence.update(image, false);
481 
482             // Images
483 
484             if (renderedImage != null) {
485                 saveImages(
486                     image.getLargeImageId(), renderedImage,
487                     image.getSmallImageId(), image.getCustom1ImageId(),
488                     image.getCustom2ImageId(), file, bytes, contentType);
489             }
490 
491             // Tags
492 
493             updateTagsAsset(userId, image, tagsEntries);
494 
495             // Lucene
496 
497             try {
498                 Indexer.updateImage(
499                     image.getCompanyId(), folder.getGroupId(),
500                     folder.getFolderId(), imageId, name, description,
501                     tagsEntries);
502             }
503             catch (SearchException se) {
504                 _log.error("Indexing " + imageId, se);
505             }
506 
507             return image;
508         }
509         catch (IOException ioe) {
510             throw new ImageSizeException(ioe);
511         }
512     }
513 
514     public void updateTagsAsset(
515             long userId, IGImage image, String[] tagsEntries)
516         throws PortalException, SystemException {
517 
518         Image largeImage = imageLocalService.getImage(image.getLargeImageId());
519 
520         if (largeImage == null) {
521             return;
522         }
523 
524         tagsAssetLocalService.updateAsset(
525             userId, image.getFolder().getGroupId(), IGImage.class.getName(),
526             image.getImageId(), tagsEntries, null, null, null, null,
527             largeImage.getType(), null, image.getDescription(), null, null,
528             largeImage.getHeight(), largeImage.getWidth(), null, false);
529     }
530 
531     protected IGFolder getFolder(IGImage image, long folderId)
532         throws PortalException, SystemException {
533 
534         if (image.getFolderId() != folderId) {
535             IGFolder oldFolder = igFolderPersistence.findByPrimaryKey(
536                 image.getFolderId());
537 
538             IGFolder newFolder = igFolderPersistence.fetchByPrimaryKey(
539                 folderId);
540 
541             if ((newFolder == null) ||
542                 (oldFolder.getGroupId() != newFolder.getGroupId())) {
543 
544                 folderId = image.getFolderId();
545             }
546         }
547 
548         return igFolderPersistence.findByPrimaryKey(folderId);
549     }
550 
551     protected void saveImages(
552             long largeImageId, RenderedImage renderedImage, long smallImageId,
553             long custom1ImageId, long custom2ImageId, File file, byte[] bytes,
554             String contentType)
555         throws SystemException {
556 
557         try {
558 
559             // Image
560 
561             imageLocalService.updateImage(largeImageId, bytes);
562 
563             // Thumbnail and custom sizes
564 
565             saveScaledImage(
566                 renderedImage, smallImageId, contentType,
567                 PropsValues.IG_IMAGE_THUMBNAIL_MAX_DIMENSION);
568 
569             if (custom1ImageId > 0) {
570                 saveScaledImage(
571                     renderedImage, custom1ImageId, contentType,
572                     PropsValues.IG_IMAGE_CUSTOM_1_MAX_DIMENSION);
573             }
574 
575             if (custom2ImageId > 0) {
576                 saveScaledImage(
577                     renderedImage, custom2ImageId, contentType,
578                     PropsValues.IG_IMAGE_CUSTOM_2_MAX_DIMENSION);
579             }
580         }
581         catch (IOException ioe) {
582             throw new SystemException(ioe);
583         }
584     }
585 
586     protected void saveScaledImage(
587             RenderedImage renderedImage, long imageId, String contentType,
588             int dimension)
589         throws IOException, SystemException {
590 
591         RenderedImage thumbnail = ImageProcessorUtil.scale(
592             renderedImage, dimension, dimension);
593 
594         ByteArrayMaker bam = new ByteArrayMaker();
595 
596         if (contentType.indexOf("bmp") != -1) {
597             ImageEncoder encoder = ImageCodec.createImageEncoder(
598                 "BMP", bam, null);
599 
600             encoder.encode(thumbnail);
601         }
602         else if (contentType.indexOf("gif") != -1) {
603             ImageProcessorUtil.encodeGIF(thumbnail, bam);
604         }
605         else if (contentType.indexOf("jpg") != -1 ||
606                  contentType.indexOf("jpeg") != -1) {
607 
608             ImageIO.write(thumbnail, "jpeg", bam);
609         }
610         else if (contentType.indexOf("png") != -1) {
611             ImageIO.write(thumbnail, "png", bam);
612         }
613         else if (contentType.indexOf("tif") != -1) {
614             ImageEncoder encoder = ImageCodec.createImageEncoder(
615                 "TIFF", bam, null);
616 
617             encoder.encode(thumbnail);
618         }
619 
620         imageLocalService.updateImage(imageId, bam.toByteArray());
621     }
622 
623     protected void validate(byte[] bytes) throws ImageSizeException {
624         if ((PropsValues.IG_IMAGE_MAX_SIZE > 0) &&
625             ((bytes == null) ||
626              (bytes.length > PropsValues.IG_IMAGE_MAX_SIZE))) {
627 
628             throw new ImageSizeException();
629         }
630     }
631 
632     protected void validate(long folderId, String nameWithExtension)
633         throws PortalException, SystemException {
634 
635         if ((nameWithExtension.indexOf("\\\\") != -1) ||
636             (nameWithExtension.indexOf("//") != -1) ||
637             (nameWithExtension.indexOf(":") != -1) ||
638             (nameWithExtension.indexOf("*") != -1) ||
639             (nameWithExtension.indexOf("?") != -1) ||
640             (nameWithExtension.indexOf("\"") != -1) ||
641             (nameWithExtension.indexOf("<") != -1) ||
642             (nameWithExtension.indexOf(">") != -1) ||
643             (nameWithExtension.indexOf("|") != -1) ||
644             (nameWithExtension.indexOf("&") != -1) ||
645             (nameWithExtension.indexOf("[") != -1) ||
646             (nameWithExtension.indexOf("]") != -1) ||
647             (nameWithExtension.indexOf("'") != -1)) {
648 
649             throw new ImageNameException();
650         }
651 
652         boolean validImageExtension = false;
653 
654         String[] imageExtensions =
655             PropsUtil.getArray(PropsKeys.IG_IMAGE_EXTENSIONS);
656 
657         for (int i = 0; i < imageExtensions.length; i++) {
658             if (StringPool.STAR.equals(imageExtensions[i]) ||
659                 StringUtil.endsWith(nameWithExtension, imageExtensions[i])) {
660 
661                 validImageExtension = true;
662 
663                 break;
664             }
665         }
666 
667         if (!validImageExtension) {
668             throw new ImageNameException();
669         }
670 
671         String name = FileUtil.stripExtension(nameWithExtension);
672         String imageType = FileUtil.getExtension(nameWithExtension);
673 
674         List<IGImage> images = igImagePersistence.findByF_N(folderId, name);
675 
676         if (imageType.equals("jpeg")) {
677             imageType = ImageProcessor.TYPE_JPEG;
678         }
679         else if (imageType.equals("tif")) {
680             imageType = ImageProcessor.TYPE_TIFF;
681         }
682 
683         for (IGImage image : images) {
684             if (imageType.equals(image.getImageType())) {
685                 throw new DuplicateImageNameException();
686             }
687         }
688     }
689 
690     protected void validate(
691             long folderId, String nameWithExtension, File file, byte[] bytes)
692         throws PortalException, SystemException {
693 
694         if (file != null) {
695             String fileName = file.getName();
696             String extension = FileUtil.getExtension(fileName);
697 
698             if (Validator.isNull(nameWithExtension)) {
699                 nameWithExtension = fileName;
700             }
701             else if (!StringUtil.endsWith(nameWithExtension, extension)) {
702                 throw new ImageNameException();
703             }
704         }
705 
706         validate(folderId, nameWithExtension);
707         validate(bytes);
708     }
709 
710     private static Log _log = LogFactory.getLog(IGImageLocalServiceImpl.class);
711 
712 }