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