/*
* JBoss, Home of Professional Open Source
* Copyright 2013, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.richfaces.photoalbum.manager;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.activation.MimetypesFileTypeMap;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.inject.Named;
import org.richfaces.event.FileUploadEvent;
import org.richfaces.model.UploadedFile;
import org.richfaces.photoalbum.model.Album;
import org.richfaces.photoalbum.model.Image;
import org.richfaces.photoalbum.model.User;
import org.richfaces.photoalbum.model.actions.IImageAction;
import org.richfaces.photoalbum.model.event.ErrorEvent;
import org.richfaces.photoalbum.model.event.EventType;
import org.richfaces.photoalbum.model.event.Events;
import org.richfaces.photoalbum.model.event.ImageEvent;
import org.richfaces.photoalbum.ui.FileWrapper;
import org.richfaces.photoalbum.util.Constants;
import org.richfaces.photoalbum.util.FileHandler;
import org.richfaces.photoalbum.util.PhotoAlbumException;
import org.richfaces.photoalbum.util.Preferred;
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import com.drew.metadata.jpeg.JpegDirectory;
/**
* Class encapsulated all functionality, related to file-upload process.
*
* @author Andrey Markhel
*/
@Named
@RequestScoped
public class FileUploadManager implements Serializable {
private static final long serialVersionUID = 4969087557225414955L;
@Inject
IImageAction imageAction;
@Inject
FileWrapper fileWrapper;
@Inject
Model model;
@Inject
@Preferred
User user;
@Inject
private FileManager fileManager;
@Inject
@EventType(Events.IMAGE_ADDED_EVENT)
Event<ImageEvent> imageEvent;
@Inject
@EventType(Events.ADD_ERROR_EVENT)
Event<ErrorEvent> error;
Logger log = Logger.getLogger("FUManager");
/**
* Listenet, that invoked during file upload process. Only registered users can upload images.
*
* @param event - event, indicated that file upload started
*/
public void listener(FileUploadEvent event) {
if (user == null) {
return;
}
UploadedFile file = event.getUploadedFile();
// Construct image from item
uploadFile(new FileHandler(file), model.getSelectedAlbum());
}
public void uploadFile(FileHandler fileHandler, Album album) {
Image image = constructImage(fileHandler);
try {
// Extract metadata(size, camera model etc..)
extractMetadata(fileHandler, image);
} catch (Exception e1) {
addError(fileHandler, image, Constants.FILE_PROCESSING_ERROR);
return;
}
image.setAlbum(album);
if (image.getAlbum() == null) {
addError(fileHandler, image, Constants.NO_ALBUM_TO_DOWNLOAD_ERROR);
return;
}
try {
// Check if image with given name already exist
if (imageAction.isImageWithThisPathExist(image.getAlbum(), image.getPath())) {
// If exist generate new path for image
String newPath = generateNewPath(image);
image.setPath(newPath);
image.setName(newPath);
}
// Save to database
imageAction.addImage(image);
} catch (Exception e) {
addError(fileHandler, image, Constants.IMAGE_SAVING_ERROR);
return;
}
try {
// Save to disk
if (!fileManager.addImage(image.getFullPath(), fileHandler)) {
addError(fileHandler, image, Constants.FILE_SAVE_ERROR);
return;
}
} catch (IOException ioe) {
log.log(Level.INFO, "error", ioe);
addError(image, Constants.FILE_SAVE_ERROR + " - " + ioe.getMessage());
}
// Prepare to show in UI
fileWrapper.setComplete(false);
fileWrapper.getFiles().add(image);
imageEvent.fire(new ImageEvent(image));
// Delete temporary file
try {
fileHandler.delete();
} catch (Exception ioe) {
log.log(Level.INFO, "error", ioe);
addError(image, "Error deleting file - " + ioe.getMessage());
}
}
private String generateNewPath(Image image) throws PhotoAlbumException {
String path = image.getPath().substring(0, image.getPath().lastIndexOf(Constants.DOT));
Long countCopies = imageAction.getCountIdenticalImages(image.getAlbum(), path) + 1;
String newPath = fileManager.transformPath(image.getPath(), "_" + countCopies);
return newPath;
}
private void addError(FileHandler fileHandler, Image image, String error) {
addError(image, error);
try {
fileHandler.delete();
} catch (Exception e) {
addError(image, e.getMessage());
}
}
private void addError(Image image, String error) {
String imageName = (image != null) ? image.getName() : "";
this.error.fire(new ErrorEvent("(" + imageName + ") " + error));
}
private Image constructImage(FileHandler fileHandler) {
long size = fileHandler.getSize();
String name = fileHandler.getName();
Image image = new Image();
image.setUploaded(new Date());
image.setDescription(name);
image.setName(name);
image.setSize(size);
image.setPath(name);
image.setAllowComments(true);
return image;
}
private void extractMetadata(FileHandler fileHandler, Image image) {
if (!MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(fileHandler.getName()).equals("image/jpeg")) {
return;
}
InputStream in = null;
try {
in = fileHandler.getInputStream();
Metadata metadata = JpegMetadataReader.readMetadata(in);
in.close();
Directory exifIFD0Directory = metadata.getDirectory(ExifIFD0Directory.class);
Directory exifSubIFDDirectory = metadata.getDirectory(ExifSubIFDDirectory.class);
Directory jpgDirectory = metadata.getDirectory(JpegDirectory.class);
if (exifIFD0Directory != null) {
setupCameraModel(image, exifIFD0Directory);
}
if (exifSubIFDDirectory != null) {
setupCreatedDate(image, exifSubIFDDirectory);
}
if (jpgDirectory != null) {
setupDimensions(image, exifSubIFDDirectory, jpgDirectory);
}
} catch (Exception e) {
addError(fileHandler, image, Constants.IMAGE_SAVING_ERROR);
} finally {
try {
in.close();
} catch (IOException e) {
addError(fileHandler, image, Constants.IMAGE_SAVING_ERROR + " - " + e.getMessage());
}
}
}
private void setupCreatedDate(Image image, Directory exifDirectory) throws MetadataException {
if (exifDirectory.containsTag(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL)) {
Date time = exifDirectory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
image.setCreated(time);
}
}
private void setupDimensions(Image image, Directory exifDirectory, Directory jpgDirectory) {
try {
if (exifDirectory != null && exifDirectory.containsTag(ExifSubIFDDirectory.TAG_EXIF_IMAGE_WIDTH)
&& exifDirectory.containsTag(ExifSubIFDDirectory.TAG_EXIF_IMAGE_HEIGHT)) {
int width = exifDirectory.getInt(ExifSubIFDDirectory.TAG_EXIF_IMAGE_WIDTH);
image.setWidth(width);
int height = exifDirectory.getInt(ExifSubIFDDirectory.TAG_EXIF_IMAGE_HEIGHT);
image.setHeight(height);
} else {
if (jpgDirectory.containsTag(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT)) {
int width = jpgDirectory.getInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH);
image.setWidth(width);
int height = jpgDirectory.getInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT);
image.setHeight(height);
}
}
} catch (MetadataException e) {
addError(image, Constants.IMAGE_SAVING_ERROR);
}
}
private void setupCameraModel(Image image, Directory exifDirectory) {
if (exifDirectory.containsTag(ExifIFD0Directory.TAG_MODEL)) {
String cameraModel = exifDirectory.getString(ExifIFD0Directory.TAG_MODEL);
image.setCameraModel(cameraModel);
} else {
image.setCameraModel("");
}
}
}