All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.adaptive.media.image.internal.handler.AMImageRequestHandler Maven / Gradle / Ivy

/**
 * SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
 * SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
 */

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 Pérez
 * @author Alejandro Tardín
 */
@Component(
	immediate = true, property = "adaptive.media.handler.pattern=image",
	service = AMRequestHandler.class
)
public class AMImageRequestHandler
	implements AMRequestHandler {

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

		Optional>
			interpretedPathOptional = _interpretPath(request.getPathInfo());

		return interpretedPathOptional.flatMap(
			tuple -> {
				Optional>
					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 _createRawAdaptiveMedia(
			FileVersion fileVersion)
		throws PortalException {

		Map properties = new HashMap<>();

		AMAttribute fileNameAMAttribute =
			AMAttribute.getFileNameAMAttribute();

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

		AMAttribute contentTypeAMAttribute =
			AMAttribute.getContentTypeAMAttribute();

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

		AMAttribute 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> _findAdaptiveMedia(
		FileVersion fileVersion,
		AMImageAttributeMapping amImageAttributeMapping) {

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

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

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

			AMImageConfigurationEntry amImageConfigurationEntry =
				amImageConfigurationEntryOptional.get();

			Optional> 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> _findClosestAdaptiveMedia(
		FileVersion fileVersion,
		AMImageConfigurationEntry amImageConfigurationEntry) {

		Map properties =
			amImageConfigurationEntry.getProperties();

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

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

		try {
			Stream> 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> _findExactAdaptiveMedia(
			FileVersion fileVersion,
			AMImageConfigurationEntry amImageConfigurationEntry)
		throws PortalException {

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

		return adaptiveMediaStream.findFirst();
	}

	private Comparator> _getComparator(
		Integer configurationWidth) {

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

	private Integer _getDistance(
		int width, AdaptiveMedia adaptiveMedia) {

		Optional imageWidthOptional = adaptiveMedia.getValueOptional(
			AMImageAttribute.AM_IMAGE_ATTRIBUTE_WIDTH);

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

		return distanceOptional.orElse(Integer.MAX_VALUE);
	}

	private Optional>
		_interpretPath(String pathInfo) {

		try {
			Optional>>
				fileVersionPropertiesTupleOptional =
					_pathInterpreter.interpretPath(pathInfo);

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

			Tuple> fileVersionMapTuple =
				fileVersionPropertiesTupleOptional.get();

			FileVersion fileVersion = fileVersionMapTuple.first;

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

			Map properties = fileVersionMapTuple.second;

			AMAttribute contentLengthAMAttribute =
				AMAttribute.getContentLengthAMAttribute();

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

			AMAttribute contentTypeAMAttribute =
				AMAttribute.getContentTypeAMAttribute();

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

			AMAttribute 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, e);

			return Optional.empty();
		}
	}

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

		Optional adaptiveMediaConfigurationUuidOptional =
			adaptiveMedia.getValueOptional(
				AMAttribute.getConfigurationUuidAMAttribute());

		Optional attributeMappingConfigurationUuidOptional =
			amImageAttributeMapping.getValueOptional(
				AMAttribute.getConfigurationUuidAMAttribute());

		if (adaptiveMediaConfigurationUuidOptional.equals(
				attributeMappingConfigurationUuidOptional)) {

			return;
		}

		try {
			AMAsyncProcessor 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;

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy