Java tutorial
package de.fhg.iais.asc.xslt.binaries; /****************************************************************************** * Copyright 2011 (c) Fraunhofer IAIS Netmedia http://www.iais.fraunhofer.de * * ************************************************************************** * * Licensed under the Apache License, Version 2.0 (the "License"); you may * * not use this file except in compliance with the License. * * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * * software distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * ******************************************************************************/ import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import org.apache.tika.detect.Detector; import org.apache.tika.metadata.Metadata; import org.apache.tika.metadata.TikaMetadataKeys; import org.apache.tika.mime.MediaType; import org.apache.tika.parser.AutoDetectParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import de.fhg.iais.asc.commons.exceptions.AscDataErrorException; import de.fhg.iais.asc.commons.exceptions.AscTechnicalErrorException; import de.fhg.iais.asc.xslt.binaries.download.Downloader; import de.fhg.iais.asc.xslt.binaries.scale.BinaryImageSize; import de.fhg.iais.asc.xslt.binaries.scale.conf.PreviewImageType; import eu.medsea.mimeutil.MimeException; import eu.medsea.mimeutil.MimeType; import eu.medsea.mimeutil.MimeUtil; import eu.medsea.mimeutil.MimeUtil2; public class DownloadAndScaleBinary { private static final String MSG_CANT_CREATE_LOCAL_PATH = "Can't create path for URI \"{}\""; private static final Logger LOG = LoggerFactory.getLogger(DownloadAndScaleBinary.class); private static final String ORIGINAL_PREFIX = "orig/"; static final String CTXKEY_PATH_CONVERT = "convert_location"; private static final boolean DOWNLOAD_PERMANENT_ONLY = true; private static final boolean DOWNLOAD_ANY = false; private final DownloadAndScaleContext context; private String mimeType; private final boolean primary; private final boolean full; private final URI downloadableURI; private final String typeSubPath; private final File permanentOriginal; private File locallyAvailableOriginal; // locally available or null private BinaryImageSize binaryImageSize; // MimeUtil2 eats up memory on each instantiation and it doesnt get released during runtime // static object helps here private static MimeUtil2 mimeUtil; static { mimeUtil = new MimeUtil2(); mimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.ExtensionMimeDetector"); mimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector"); } public DownloadAndScaleBinary(DownloadAndScaleContext context, String pathOrUrl, String localPath, boolean primary, boolean full) { this.context = context; this.primary = primary; this.full = full; this.downloadableURI = Downloader.createDownloadableURI(pathOrUrl); if (this.downloadableURI == null) { this.typeSubPath = pathOrUrl; } else { this.typeSubPath = findLocalPath(localPath, this.downloadableURI); } File binaryRoot = this.context.getBinaryRoot(); this.permanentOriginal = new File(binaryRoot, ORIGINAL_PREFIX + this.typeSubPath); if (this.permanentOriginal.isFile() || moveToPermanentOriginal()) { this.locallyAvailableOriginal = this.permanentOriginal; } } public DownloadAndScaleBinary(DownloadAndScaleContext context, URI uri, String localPathname, boolean primary, boolean full) { this.context = context; this.primary = primary; this.full = full; this.downloadableURI = uri; this.typeSubPath = determineTypeSubPath(uri, localPathname); File binaryRoot = this.context.getBinaryRoot(); this.permanentOriginal = new File(binaryRoot, ORIGINAL_PREFIX + this.typeSubPath); if (this.permanentOriginal.isFile() || moveToPermanentOriginal()) { this.locallyAvailableOriginal = this.permanentOriginal; } } public String getTypeSubPath() { return this.typeSubPath; } private String determineTypeSubPath(URI uri, String localPathname) { if (StringUtils.isNotEmpty(localPathname)) { return localPathname; } if (uri != null) { String fromURI = Downloader.createPathFromURI(uri); if (StringUtils.isNotEmpty(fromURI)) { return fromURI; } } final String msg = String.format(MSG_CANT_CREATE_LOCAL_PATH, ObjectUtils.toString(uri)); throw new AscDataErrorException(msg); } private static String findLocalPath(String localPath, URI uri) { return StringUtils.isNotEmpty(localPath) ? localPath : Downloader.createPathFromURI(uri); } public DownloadAndScaleBinary setMimeType(String mimeType) { // from mapper this.mimeType = mimeType; return this; } public String getMimeType() { // from mapper or tika if the mapper didn't specify the mimetype return this.mimeType; } private boolean moveToPermanentOriginal() { File binaryRoot = this.context.getBinaryRoot(); File f = new File(binaryRoot, this.typeSubPath); if (f.isFile()) { try { FileUtils.moveFile(f, this.permanentOriginal); return true; } catch (IOException e) { String srcPath = f.getAbsolutePath(); String destPath = this.permanentOriginal.getAbsolutePath(); String msg = String.format("Can't move file \"%s\" to \"%s\"", srcPath, destPath); throw new AscTechnicalErrorException(msg); } } return false; } public List<Object> createAllVariants(List<PreviewImageType> previewTypes) { List<Object> result = new ArrayList<Object>(); if (this.context.isTypeAllowed("orig")) { makeOriginalLocallyAvailable(DOWNLOAD_PERMANENT_ONLY); } if ((this.mimeType == null) || (this.mimeType.equals(""))) { this.mimeType = detectMimetype(); if (this.mimeType.equals("video/quicktime")) { this.mimeType = "video/mp4"; } } if (this.mimeType.startsWith("audio/") || this.mimeType.startsWith("video/") || this.mimeType.equals("application/pdf")) { // is audio, video or pdf if (this.mimeType.equals("video/vimeo")) { // if external video result.add(this.typeSubPath); } else if (this.locallyAvailableOriginal == this.permanentOriginal) { String filepath = "full" + "/" + this.typeSubPath; result.add(filepath); File binary = new File(this.context.getBinaryRoot() + "/" + filepath); try { FileUtils.copyFile(this.locallyAvailableOriginal, binary); } catch (IOException e) { LOG.error("Can't create directory 'full': " + e); } } else if (this.downloadableURI != null) { result.add(this.downloadableURI); } } else if (!this.mimeType.startsWith("image/")) { if (this.locallyAvailableOriginal != null) { this.locallyAvailableOriginal.delete(); } } if ((this.mimeType.startsWith("image/") || (this.mimeType.equals("application/pdf")))) { // is image or pdf if (this.context.isAnyScaleAllowed()) { for (PreviewImageType previewType : previewTypes) { if (isPreviewAllowed(previewType)) { final String previewTypeName = previewType.getType(); String scaled = previewTypeName + "/" + FilenameUtils.removeExtension(this.typeSubPath) + ".jpg"; if (executeScale(previewType, scaled, this.mimeType)) { result.add(scaled); } else { // delete file if scaling could not be executed (e.g. damaged image) if (this.locallyAvailableOriginal != null) { this.locallyAvailableOriginal.delete(); } } } } } } return result; } private String detectMimetype() { String mimetype = ""; if (this.locallyAvailableOriginal == null) { return mimetype; } FileInputStream is = null; BufferedInputStream bis = null; MediaType mediaType = null; try { try { is = new FileInputStream(this.locallyAvailableOriginal); bis = new BufferedInputStream(is); AutoDetectParser parser = new AutoDetectParser(); Detector detector = parser.getDetector(); Metadata md = new Metadata(); md.add(TikaMetadataKeys.RESOURCE_NAME_KEY, this.locallyAvailableOriginal.getName()); mediaType = detector.detect(bis, md); } catch (FileNotFoundException e) { LOG.error("Can't find file: \"" + this.locallyAvailableOriginal.getAbsolutePath(), e); } } catch (IOException e) { LOG.error("Can't read file: \"" + this.locallyAvailableOriginal.getAbsolutePath(), e); } finally { IOUtils.closeQuietly(bis); IOUtils.closeQuietly(is); } return mediaType.toString(); } private boolean executeScale(PreviewImageType previewType, String scaled, String mimetype) { if (null == makeOriginalLocallyAvailable(DOWNLOAD_ANY)) { return false; } return this.context.createScaled(this.locallyAvailableOriginal, scaled, previewType, mimetype); } private boolean isPreviewAllowed(PreviewImageType previewType) { String typeName = previewType.getType(); if (this.mimeType.equals("application/pdf") && typeName.equals("full")) { return false; } if (typeName.equals("full") && !this.full) { return false; } return previewType.isAllowedForPrimaryValue(this.primary) && this.context.isTypeAllowed(typeName) && deepCheckIsImage() && checkMinimumOriginalSize(previewType); } private boolean isImageWithDefault(boolean resultForEmptyMimeType) { String mimeType = this.mimeType; return StringUtils.isEmpty(mimeType) ? resultForEmptyMimeType : (mimeType.startsWith("image/") || (this.mimeType.equals("application/pdf"))); } private boolean deepCheckIsImage() { if (StringUtils.isEmpty(this.mimeType)) { if (null != makeOriginalLocallyAvailable(DOWNLOAD_ANY)) { try { synchronized (mimeUtil) { Collection<?> mimeTypes = mimeUtil.getMimeTypes(this.locallyAvailableOriginal); MimeType type = MimeUtil.getMostSpecificMimeType(mimeTypes); this.mimeType = type.toString(); } } catch (MimeException e) { LOG.warn("Can't detect MIME type for file \"" + this.locallyAvailableOriginal.getAbsolutePath() + "\"", e); } } } return isImageWithDefault(false); } private boolean checkMinimumOriginalSize(PreviewImageType previewType) { BinaryImageSize minOriginalSize = previewType.getMinOriginalSize(); if (minOriginalSize == null) { return true; } if (this.mimeType.equals("application/pdf")) { return true; } final BinaryImageSize binaryImageSize = determineBinaryImageSize(); if (binaryImageSize == null) { return false; } return (binaryImageSize.getWidth() >= minOriginalSize.getWidth()) || (binaryImageSize.getHeight() >= minOriginalSize.getHeight()); } private BinaryImageSize determineBinaryImageSize() { if ((this.binaryImageSize == null) && deepCheckIsImage()) { if (null != makeOriginalLocallyAvailable(DOWNLOAD_ANY)) { try { this.binaryImageSize = BinaryImageSize.of(this.locallyAvailableOriginal); } catch (IOException e) { String path = this.locallyAvailableOriginal.getAbsolutePath(); LOG.error("Can't read image size of \"" + path + "\"", e); } } } return this.binaryImageSize; } public File makeOriginalLocallyAvailable(boolean permanentOnly) { if ((this.downloadableURI != null) && (this.locallyAvailableOriginal == null)) { this.locallyAvailableOriginal = this.context.downloadFile(this.downloadableURI, this.permanentOriginal, permanentOnly); } return this.locallyAvailableOriginal; } }