com.liferay.adaptive.media.image.internal.handler.AMImageRequestHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.adaptive.media.image.internal.handler.AMImageRequestHandler.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library 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 library 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.
 */

package com.liferay.adaptive.media.image.internal.handler;

import com.liferay.adaptive.media.AMAttribute;
import com.liferay.adaptive.media.AdaptiveMedia;
import com.liferay.adaptive.media.exception.AMRuntimeException;
import com.liferay.adaptive.media.handler.AMRequestHandler;
import com.liferay.adaptive.media.image.configuration.AMImageConfigurationEntry;
import com.liferay.adaptive.media.image.configuration.AMImageConfigurationHelper;
import com.liferay.adaptive.media.image.finder.AMImageFinder;
import com.liferay.adaptive.media.image.internal.configuration.AMImageAttributeMapping;
import com.liferay.adaptive.media.image.internal.processor.AMImage;
import com.liferay.adaptive.media.image.internal.util.Tuple;
import com.liferay.adaptive.media.image.processor.AMImageAttribute;
import com.liferay.adaptive.media.image.processor.AMImageProcessor;
import com.liferay.adaptive.media.processor.AMAsyncProcessor;
import com.liferay.adaptive.media.processor.AMAsyncProcessorLocator;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.repository.model.FileVersion;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.workflow.WorkflowConstants;

import java.io.IOException;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

/**
 * @author Adolfo Prez
 * @author Alejandro Tardn
 */
@Component(immediate = true, property = "adaptive.media.handler.pattern=image", service = AMRequestHandler.class)
public class AMImageRequestHandler implements AMRequestHandler<AMImageProcessor> {

    @Override
    public Optional<AdaptiveMedia<AMImageProcessor>> handleRequest(HttpServletRequest request)
            throws IOException, ServletException {

        Optional<Tuple<FileVersion, AMImageAttributeMapping>> interpretedPathOptional = _interpretPath(
                request.getPathInfo());

        return interpretedPathOptional.flatMap(tuple -> {
            Optional<AdaptiveMedia<AMImageProcessor>> adaptiveMediaOptional = _findAdaptiveMedia(tuple.first,
                    tuple.second);

            adaptiveMediaOptional
                    .ifPresent(adaptiveMedia -> _processAMImage(adaptiveMedia, tuple.first, tuple.second));

            return adaptiveMediaOptional;
        });
    }

    @Reference(unbind = "-")
    public void setAMAsyncProcessorLocator(AMAsyncProcessorLocator amAsyncProcessorLocator) {

        _amAsyncProcessorLocator = amAsyncProcessorLocator;
    }

    @Reference(unbind = "-")
    public void setAMImageConfigurationHelper(AMImageConfigurationHelper amImageConfigurationHelper) {

        _amImageConfigurationHelper = amImageConfigurationHelper;
    }

    @Reference(unbind = "-")
    public void setAMImageFinder(AMImageFinder amImageFinder) {
        _amImageFinder = amImageFinder;
    }

    @Reference(unbind = "-")
    public void setPathInterpreter(PathInterpreter pathInterpreter) {
        _pathInterpreter = pathInterpreter;
    }

    private AdaptiveMedia<AMImageProcessor> _createRawAdaptiveMedia(FileVersion fileVersion)
            throws PortalException {

        Map<String, String> properties = new HashMap<>();

        AMAttribute<Object, String> fileNameAMAttribute = AMAttribute.getFileNameAMAttribute();

        properties.put(fileNameAMAttribute.getName(), fileVersion.getFileName());

        AMAttribute<Object, String> contentTypeAMAttribute = AMAttribute.getContentTypeAMAttribute();

        properties.put(contentTypeAMAttribute.getName(), fileVersion.getMimeType());

        AMAttribute<Object, Long> contentLengthAMAttribute = AMAttribute.getContentLengthAMAttribute();

        properties.put(contentLengthAMAttribute.getName(), String.valueOf(fileVersion.getSize()));

        return new AMImage(() -> {
            try {
                return fileVersion.getContentStream(false);
            } catch (PortalException pe) {
                throw new AMRuntimeException(pe);
            }
        }, AMImageAttributeMapping.fromProperties(properties), null);
    }

    private Optional<AdaptiveMedia<AMImageProcessor>> _findAdaptiveMedia(FileVersion fileVersion,
            AMImageAttributeMapping amImageAttributeMapping) {

        try {
            Optional<String> valueOptional = amImageAttributeMapping
                    .getValueOptional(AMAttribute.getConfigurationUuidAMAttribute());

            Optional<AMImageConfigurationEntry> amImageConfigurationEntryOptional = valueOptional
                    .flatMap(configurationUuid -> _amImageConfigurationHelper
                            .getAMImageConfigurationEntry(fileVersion.getCompanyId(), configurationUuid));

            if (!amImageConfigurationEntryOptional.isPresent()) {
                return Optional.empty();
            }

            AMImageConfigurationEntry amImageConfigurationEntry = amImageConfigurationEntryOptional.get();

            Optional<AdaptiveMedia<AMImageProcessor>> adaptiveMediaOptional = _findExactAdaptiveMedia(fileVersion,
                    amImageConfigurationEntry);

            if (adaptiveMediaOptional.isPresent()) {
                return adaptiveMediaOptional;
            }

            adaptiveMediaOptional = _findClosestAdaptiveMedia(fileVersion, amImageConfigurationEntry);

            if (adaptiveMediaOptional.isPresent()) {
                return adaptiveMediaOptional;
            }

            return Optional.of(_createRawAdaptiveMedia(fileVersion));
        } catch (PortalException pe) {
            throw new AMRuntimeException(pe);
        }
    }

    private Optional<AdaptiveMedia<AMImageProcessor>> _findClosestAdaptiveMedia(FileVersion fileVersion,
            AMImageConfigurationEntry amImageConfigurationEntry) {

        Map<String, String> properties = amImageConfigurationEntry.getProperties();

        final Integer configurationWidth = GetterUtil.getInteger(properties.get("max-width"));

        final Integer configurationHeight = GetterUtil.getInteger(properties.get("max-height"));

        try {
            Stream<AdaptiveMedia<AMImageProcessor>> adaptiveMediaStream = _amImageFinder
                    .getAdaptiveMediaStream(amImageQueryBuilder -> amImageQueryBuilder.forFileVersion(fileVersion)
                            .with(AMImageAttribute.AM_IMAGE_ATTRIBUTE_WIDTH, configurationWidth)
                            .with(AMImageAttribute.AM_IMAGE_ATTRIBUTE_HEIGHT, configurationHeight).done());

            return adaptiveMediaStream.sorted(_getComparator(configurationWidth)).findFirst();
        } catch (PortalException pe) {
            throw new AMRuntimeException(pe);
        }
    }

    private Optional<AdaptiveMedia<AMImageProcessor>> _findExactAdaptiveMedia(FileVersion fileVersion,
            AMImageConfigurationEntry amImageConfigurationEntry) throws PortalException {

        Stream<AdaptiveMedia<AMImageProcessor>> adaptiveMediaStream = _amImageFinder
                .getAdaptiveMediaStream(amImageQueryBuilder -> amImageQueryBuilder.forFileVersion(fileVersion)
                        .forConfiguration(amImageConfigurationEntry.getUUID()).done());

        return adaptiveMediaStream.findFirst();
    }

    private Comparator<AdaptiveMedia<AMImageProcessor>> _getComparator(Integer configurationWidth) {

        return Comparator.comparingInt(adaptiveMedia -> _getDistance(configurationWidth, adaptiveMedia));
    }

    private Integer _getDistance(int width, AdaptiveMedia<AMImageProcessor> adaptiveMedia) {

        Optional<Integer> imageWidthOptional = adaptiveMedia
                .getValueOptional(AMImageAttribute.AM_IMAGE_ATTRIBUTE_WIDTH);

        Optional<Integer> distanceOptional = imageWidthOptional.map(imageWidth -> Math.abs(imageWidth - width));

        return distanceOptional.orElse(Integer.MAX_VALUE);
    }

    private Optional<Tuple<FileVersion, AMImageAttributeMapping>> _interpretPath(String pathInfo) {

        try {
            Optional<Tuple<FileVersion, Map<String, String>>> fileVersionPropertiesTupleOptional = _pathInterpreter
                    .interpretPath(pathInfo);

            if (!fileVersionPropertiesTupleOptional.isPresent()) {
                return Optional.empty();
            }

            Tuple<FileVersion, Map<String, String>> fileVersionMapTuple = fileVersionPropertiesTupleOptional.get();

            FileVersion fileVersion = fileVersionMapTuple.first;

            if (fileVersion.getStatus() == WorkflowConstants.STATUS_IN_TRASH) {
                return Optional.empty();
            }

            Map<String, String> properties = fileVersionMapTuple.second;

            AMAttribute<Object, Long> contentLengthAMAttribute = AMAttribute.getContentLengthAMAttribute();

            properties.put(contentLengthAMAttribute.getName(), String.valueOf(fileVersion.getSize()));

            AMAttribute<Object, String> contentTypeAMAttribute = AMAttribute.getContentTypeAMAttribute();

            properties.put(contentTypeAMAttribute.getName(), fileVersion.getMimeType());

            AMAttribute<Object, String> fileNameAMAttribute = AMAttribute.getFileNameAMAttribute();

            properties.put(fileNameAMAttribute.getName(), fileVersion.getFileName());

            AMImageAttributeMapping amImageAttributeMapping = AMImageAttributeMapping.fromProperties(properties);

            return Optional.of(Tuple.of(fileVersion, amImageAttributeMapping));
        } catch (AMRuntimeException | NumberFormatException e) {
            _log.error(e);

            return Optional.empty();
        }
    }

    private void _processAMImage(AdaptiveMedia<AMImageProcessor> adaptiveMedia, FileVersion fileVersion,
            AMImageAttributeMapping amImageAttributeMapping) {

        Optional<String> adaptiveMediaConfigurationUuidOptional = adaptiveMedia
                .getValueOptional(AMAttribute.getConfigurationUuidAMAttribute());

        Optional<String> attributeMappingConfigurationUuidOptional = amImageAttributeMapping
                .getValueOptional(AMAttribute.getConfigurationUuidAMAttribute());

        if (adaptiveMediaConfigurationUuidOptional.equals(attributeMappingConfigurationUuidOptional)) {

            return;
        }

        try {
            AMAsyncProcessor<FileVersion, ?> amAsyncProcessor = _amAsyncProcessorLocator
                    .locateForClass(FileVersion.class);

            amAsyncProcessor.triggerProcess(fileVersion, String.valueOf(fileVersion.getFileVersionId()));
        } catch (PortalException pe) {
            _log.error("Unable to create lazy adaptive media for file version " + fileVersion.getFileVersionId(),
                    pe);
        }
    }

    private static final Log _log = LogFactoryUtil.getLog(AMImageRequestHandler.class);

    private AMAsyncProcessorLocator _amAsyncProcessorLocator;
    private AMImageConfigurationHelper _amImageConfigurationHelper;
    private AMImageFinder _amImageFinder;
    private PathInterpreter _pathInterpreter;

}