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