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

com.liferay.sync.internal.servlet.SyncDownloadServlet Maven / Gradle / Ivy

The newest version!
/**
 * 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.sync.internal.servlet;

import com.liferay.document.library.kernel.exception.NoSuchFileEntryException;
import com.liferay.document.library.kernel.exception.NoSuchFileVersionException;
import com.liferay.document.library.kernel.model.DLFileVersion;
import com.liferay.document.library.kernel.service.DLAppService;
import com.liferay.document.library.kernel.service.DLFileEntryLocalService;
import com.liferay.document.library.kernel.service.DLFileVersionLocalService;
import com.liferay.petra.string.CharPool;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.exception.NoSuchImageException;
import com.liferay.portal.kernel.json.JSONArray;
import com.liferay.portal.kernel.json.JSONFactory;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.json.JSONUtil;
import com.liferay.portal.kernel.model.Group;
import com.liferay.portal.kernel.model.Image;
import com.liferay.portal.kernel.model.ImageConstants;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.portletfilerepository.PortletFileRepositoryUtil;
import com.liferay.portal.kernel.repository.model.FileEntry;
import com.liferay.portal.kernel.repository.model.FileVersion;
import com.liferay.portal.kernel.repository.model.Folder;
import com.liferay.portal.kernel.security.permission.PermissionCheckerFactoryUtil;
import com.liferay.portal.kernel.security.permission.PermissionThreadLocal;
import com.liferay.portal.kernel.service.GroupLocalService;
import com.liferay.portal.kernel.service.ImageLocalService;
import com.liferay.portal.kernel.service.UserLocalService;
import com.liferay.portal.kernel.servlet.HttpHeaders;
import com.liferay.portal.kernel.servlet.PortalSessionThreadLocal;
import com.liferay.portal.kernel.servlet.ServletResponseUtil;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.HttpComponentsUtil;
import com.liferay.portal.kernel.util.MimeTypesUtil;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.Portal;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.zip.ZipWriter;
import com.liferay.portal.kernel.zip.ZipWriterFactory;
import com.liferay.sync.SyncSiteUnavailableException;
import com.liferay.sync.internal.configuration.SyncServiceConfigurationValues;
import com.liferay.sync.model.SyncDLFileVersionDiff;
import com.liferay.sync.model.SyncDevice;
import com.liferay.sync.service.SyncDLFileVersionDiffLocalServiceUtil;
import com.liferay.sync.service.SyncDeviceLocalServiceUtil;
import com.liferay.sync.util.SyncHelper;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import java.util.List;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

/**
 * @author Dennis Ju
 */
@Component(
	immediate = true,
	property = {
		"osgi.http.whiteboard.context.path=/sync",
		"osgi.http.whiteboard.servlet.name=com.liferay.sync.internal.servlet.SyncDownloadServlet",
		"osgi.http.whiteboard.servlet.pattern=/sync/download/*"
	},
	service = Servlet.class
)
public class SyncDownloadServlet extends HttpServlet {

	@Override
	public void service(
			HttpServletRequest httpServletRequest,
			HttpServletResponse httpServletResponse)
		throws IOException, ServletException {

		try {
			if (PortalSessionThreadLocal.getHttpSession() == null) {
				PortalSessionThreadLocal.setHttpSession(
					httpServletRequest.getSession());
			}

			User user = _portal.getUser(httpServletRequest);

			String syncUuid = httpServletRequest.getHeader("Sync-UUID");

			if (syncUuid != null) {
				SyncDevice syncDevice =
					SyncDeviceLocalServiceUtil.
						fetchSyncDeviceByUuidAndCompanyId(
							syncUuid, user.getCompanyId());

				if (syncDevice != null) {
					syncDevice.checkStatus();
				}
			}

			PermissionThreadLocal.setPermissionChecker(
				PermissionCheckerFactoryUtil.create(user));

			String path = HttpComponentsUtil.fixPath(
				httpServletRequest.getPathInfo());

			String[] pathArray = StringUtil.split(path, CharPool.SLASH);

			if (pathArray[0].equals("image")) {
				long imageId = GetterUtil.getLong(pathArray[1]);

				_sendImage(httpServletRequest, httpServletResponse, imageId);
			}
			else if (pathArray[0].equals("zip")) {
				String zipFileIds = ParamUtil.get(
					httpServletRequest, "zipFileIds", StringPool.BLANK);

				if (Validator.isNull(zipFileIds)) {
					throw new IllegalArgumentException(
						"Missing parameter zipFileIds");
				}

				JSONArray zipFileIdsJSONArray = _jsonFactory.createJSONArray(
					zipFileIds);

				_sendZipFile(httpServletResponse, zipFileIdsJSONArray);
			}
			else if (pathArray[0].equals("zipfolder")) {
				long repositoryId = ParamUtil.getLong(
					httpServletRequest, "repositoryId");
				long folderId = ParamUtil.getLong(
					httpServletRequest, "folderId");

				if (repositoryId == 0) {
					throw new IllegalArgumentException(
						"Missing parameter repositoryId");
				}
				else if (folderId == 0) {
					throw new IllegalArgumentException(
						"Missing parameter folderId");
				}

				_sendZipFolder(
					httpServletResponse, user.getUserId(), repositoryId,
					folderId);
			}
			else {
				long groupId = GetterUtil.getLong(pathArray[0]);

				Group group = _groupLocalService.fetchGroup(groupId);

				if ((group == null) || !_syncHelper.isSyncEnabled(group)) {
					httpServletResponse.setHeader(
						_ERROR_HEADER,
						SyncSiteUnavailableException.class.getName());

					ServletResponseUtil.write(httpServletResponse, new byte[0]);

					return;
				}

				String fileUuid = pathArray[1];

				if (ParamUtil.getBoolean(httpServletRequest, "patch")) {
					_sendPatch(
						httpServletRequest, httpServletResponse, groupId,
						fileUuid);
				}
				else {
					_sendFile(
						httpServletRequest, httpServletResponse, groupId,
						fileUuid);
				}
			}
		}
		catch (NoSuchFileEntryException noSuchFileEntryException) {
			_portal.sendError(
				HttpServletResponse.SC_NOT_FOUND, noSuchFileEntryException,
				httpServletRequest, httpServletResponse);
		}
		catch (NoSuchFileVersionException noSuchFileVersionException) {
			_portal.sendError(
				HttpServletResponse.SC_NOT_FOUND, noSuchFileVersionException,
				httpServletRequest, httpServletResponse);
		}
		catch (Exception exception) {
			_portal.sendError(
				exception, httpServletRequest, httpServletResponse);
		}
	}

	@Reference(unbind = "-")
	protected void setDLAppService(DLAppService dlAppService) {
		_dlAppService = dlAppService;
	}

	@Reference(unbind = "-")
	protected void setDlFileEntryLocalService(
		DLFileEntryLocalService dlFileEntryLocalService) {

		_dlFileEntryLocalService = dlFileEntryLocalService;
	}

	@Reference(unbind = "-")
	protected void setDlFileVersionLocalService(
		DLFileVersionLocalService dlFileVersionLocalService) {

		_dlFileVersionLocalService = dlFileVersionLocalService;
	}

	@Reference(unbind = "-")
	protected void setGroupLocalService(GroupLocalService groupLocalService) {
		_groupLocalService = groupLocalService;
	}

	@Reference(unbind = "-")
	protected void setImageLocalService(ImageLocalService imageLocalService) {
		_imageLocalService = imageLocalService;
	}

	@Reference(unbind = "-")
	protected void setUserLocalService(UserLocalService userLocalService) {
		_userLocalService = userLocalService;
	}

	private void _addZipFolderEntry(
			long userId, long repositoryId, long folderId, String folderPath,
			ZipWriter zipWriter)
		throws Exception {

		List fileEntries = _dlAppService.getFileEntries(
			repositoryId, folderId);

		for (FileEntry fileEntry : fileEntries) {
			try (InputStream inputStream =
					_dlFileEntryLocalService.getFileAsStream(
						fileEntry.getFileEntryId(), fileEntry.getVersion(),
						false)) {

				String filePath = folderPath + fileEntry.getTitle();

				zipWriter.addEntry(filePath, inputStream);
			}
		}

		List childFolders = _dlAppService.getFolders(
			repositoryId, folderId);

		for (Folder childFolder : childFolders) {
			String childFolderPath =
				folderPath + childFolder.getName() + StringPool.FORWARD_SLASH;

			_addZipFolderEntry(
				userId, repositoryId, childFolder.getFolderId(),
				childFolderPath, zipWriter);
		}
	}

	private File _getDeltaFile(
			long fileEntryId, long sourceVersionId, long targetVersionId)
		throws Exception {

		DLFileVersion sourceDLFileVersion =
			_dlFileVersionLocalService.getDLFileVersion(sourceVersionId);

		File sourceFile = FileUtil.createTempFile(
			_dlFileEntryLocalService.getFileAsStream(
				fileEntryId, sourceDLFileVersion.getVersion(), false));

		DLFileVersion targetDLFileVersion =
			_dlFileVersionLocalService.getDLFileVersion(targetVersionId);

		File targetFile = FileUtil.createTempFile(
			_dlFileEntryLocalService.getFileAsStream(
				fileEntryId, targetDLFileVersion.getVersion(), false));

		try {
			return _syncHelper.getFileDelta(sourceFile, targetFile);
		}
		finally {
			sourceFile.delete();

			targetFile.delete();
		}
	}

	private DownloadServletInputStream _getFileDownloadServletInputStream(
			long groupId, String uuid, String version, long versionId)
		throws Exception {

		FileEntry fileEntry = _dlAppService.getFileEntryByUuidAndGroupId(
			uuid, groupId);

		if (fileEntry.isInTrash()) {
			throw new NoSuchFileEntryException();
		}

		if (Validator.isNull(version)) {
			InputStream inputStream = _dlFileEntryLocalService.getFileAsStream(
				fileEntry.getFileEntryId(), fileEntry.getVersion(), false);

			return new DownloadServletInputStream(
				inputStream, fileEntry.getFileName(), fileEntry.getMimeType(),
				fileEntry.getSize());
		}

		if (versionId > 0) {
			DLFileVersion dlFileVersion =
				_dlFileVersionLocalService.fetchDLFileVersion(versionId);

			return new DownloadServletInputStream(
				dlFileVersion.getContentStream(false),
				dlFileVersion.getFileName(), dlFileVersion.getMimeType(),
				dlFileVersion.getSize());
		}

		FileVersion fileVersion = fileEntry.getFileVersion(version);

		return new DownloadServletInputStream(
			fileVersion.getContentStream(false), fileVersion.getFileName(),
			fileVersion.getMimeType(), fileVersion.getSize());
	}

	private DownloadServletInputStream _getPatchDownloadServletInputStream(
			long groupId, String uuid, long sourceVersionId,
			long targetVersionId)
		throws Exception {

		FileEntry fileEntry = _dlAppService.getFileEntryByUuidAndGroupId(
			uuid, groupId);

		if (fileEntry.isInTrash()) {
			throw new NoSuchFileEntryException();
		}

		if (!SyncServiceConfigurationValues.SYNC_FILE_DIFF_CACHE_ENABLED) {
			File deltaFile = null;

			try {
				deltaFile = _getDeltaFile(
					fileEntry.getFileEntryId(), sourceVersionId,
					targetVersionId);

				return new DownloadServletInputStream(
					new FileInputStream(deltaFile), deltaFile.length());
			}
			finally {
				FileUtil.delete(deltaFile);
			}
		}

		SyncDLFileVersionDiff syncDLFileVersionDiff =
			SyncDLFileVersionDiffLocalServiceUtil.fetchSyncDLFileVersionDiff(
				fileEntry.getFileEntryId(), sourceVersionId, targetVersionId);

		if (syncDLFileVersionDiff != null) {
			SyncDLFileVersionDiffLocalServiceUtil.refreshExpirationDate(
				syncDLFileVersionDiff.getSyncDLFileVersionDiffId());

			FileEntry dataFileEntry =
				PortletFileRepositoryUtil.getPortletFileEntry(
					syncDLFileVersionDiff.getDataFileEntryId());

			return new DownloadServletInputStream(
				dataFileEntry.getContentStream(), dataFileEntry.getSize());
		}

		File deltaFile = null;

		try {
			deltaFile = _getDeltaFile(
				fileEntry.getFileEntryId(), sourceVersionId, targetVersionId);

			SyncDLFileVersionDiffLocalServiceUtil.addSyncDLFileVersionDiff(
				fileEntry.getFileEntryId(), sourceVersionId, targetVersionId,
				deltaFile);

			return new DownloadServletInputStream(
				new FileInputStream(deltaFile), deltaFile.length());
		}
		finally {
			FileUtil.delete(deltaFile);
		}
	}

	private InputStream _getZipFileInputStream(
			JSONObject zipObjectJSONObject, long groupId)
		throws Exception {

		String uuid = zipObjectJSONObject.getString("uuid");

		if (zipObjectJSONObject.getBoolean("patch")) {
			long sourceVersionId = zipObjectJSONObject.getLong(
				"sourceVersionId", 0);
			long targetVersionId = zipObjectJSONObject.getLong(
				"targetVersionId", 0);

			return _getPatchDownloadServletInputStream(
				groupId, uuid, sourceVersionId, targetVersionId);
		}

		return _getFileDownloadServletInputStream(
			groupId, uuid, zipObjectJSONObject.getString("version"),
			zipObjectJSONObject.getLong("versionId"));
	}

	private void _processException(
		String zipFileId, String exception, JSONObject errorsJSONObject) {

		JSONObject exceptionJSONObject = JSONUtil.put("exception", exception);

		errorsJSONObject.put(zipFileId, exceptionJSONObject);
	}

	private void _sendFile(
			HttpServletRequest httpServletRequest,
			HttpServletResponse httpServletResponse, long groupId, String uuid)
		throws Exception {

		String version = ParamUtil.getString(httpServletRequest, "version");
		long versionId = ParamUtil.getLong(httpServletRequest, "versionId");

		DownloadServletInputStream downloadServletInputStream =
			_getFileDownloadServletInputStream(
				groupId, uuid, version, versionId);

		if (httpServletRequest.getHeader(HttpHeaders.RANGE) != null) {
			ServletResponseUtil.sendFileWithRangeHeader(
				httpServletRequest, httpServletResponse,
				downloadServletInputStream.getFileName(),
				downloadServletInputStream,
				downloadServletInputStream.getSize(),
				downloadServletInputStream.getMimeType());
		}
		else {
			ServletResponseUtil.write(
				httpServletResponse, downloadServletInputStream,
				downloadServletInputStream.getSize());
		}
	}

	private void _sendImage(
			HttpServletRequest httpServletRequest,
			HttpServletResponse httpServletResponse, long imageId)
		throws Exception {

		User user = _userLocalService.fetchUser(imageId);

		if (user != null) {
			imageId = user.getPortraitId();
		}

		Image image = _imageLocalService.fetchImage(imageId);

		if (image == null) {
			_portal.sendError(
				HttpServletResponse.SC_NOT_FOUND, new NoSuchImageException(),
				httpServletRequest, httpServletResponse);

			return;
		}

		String type = image.getType();

		if (!type.equals(ImageConstants.TYPE_NOT_AVAILABLE)) {
			httpServletResponse.setContentType(
				MimeTypesUtil.getExtensionContentType(type));
		}

		ServletResponseUtil.write(httpServletResponse, image.getTextObj());
	}

	private void _sendPatch(
			HttpServletRequest httpServletRequest,
			HttpServletResponse httpServletResponse, long groupId, String uuid)
		throws Exception {

		long sourceVersionId = ParamUtil.getLong(
			httpServletRequest, "sourceVersionId");
		long targetVersionId = ParamUtil.getLong(
			httpServletRequest, "targetVersionId");

		DownloadServletInputStream downloadServletInputStream =
			_getPatchDownloadServletInputStream(
				groupId, uuid, sourceVersionId, targetVersionId);

		ServletResponseUtil.write(
			httpServletResponse, downloadServletInputStream,
			downloadServletInputStream.getSize());
	}

	private void _sendZipFile(
			HttpServletResponse httpServletResponse,
			JSONArray zipFileIdsJSONArray)
		throws Exception {

		ZipWriter zipWriter = _zipWriterFactory.getZipWriter();

		JSONObject errorsJSONObject = _jsonFactory.createJSONObject();

		for (int i = 0; i < zipFileIdsJSONArray.length(); i++) {
			JSONObject zipObjectJSONObject = zipFileIdsJSONArray.getJSONObject(
				i);

			long groupId = zipObjectJSONObject.getLong("groupId");
			String zipFileId = zipObjectJSONObject.getString("zipFileId");

			Group group = _groupLocalService.fetchGroup(groupId);

			if ((group == null) || !_syncHelper.isSyncEnabled(group)) {
				_processException(
					zipFileId, SyncSiteUnavailableException.class.getName(),
					errorsJSONObject);

				continue;
			}

			try (InputStream inputStream = _getZipFileInputStream(
					zipObjectJSONObject, groupId)) {

				zipWriter.addEntry(zipFileId, inputStream);
			}
			catch (Exception exception) {
				Class clazz = exception.getClass();

				_processException(zipFileId, clazz.getName(), errorsJSONObject);
			}
		}

		zipWriter.addEntry("errors.json", errorsJSONObject.toString());

		File file = zipWriter.getFile();

		ServletResponseUtil.write(
			httpServletResponse, new FileInputStream(file), file.length());
	}

	private void _sendZipFolder(
			HttpServletResponse httpServletResponse, long userId,
			long repositoryId, long folderId)
		throws Exception {

		ZipWriter zipWriter = _zipWriterFactory.getZipWriter();

		_addZipFolderEntry(
			userId, repositoryId, folderId, StringPool.BLANK, zipWriter);

		File file = zipWriter.getFile();

		ServletResponseUtil.write(
			httpServletResponse, new FileInputStream(file), file.length());
	}

	private static final String _ERROR_HEADER = "Sync-Error";

	private DLAppService _dlAppService;
	private DLFileEntryLocalService _dlFileEntryLocalService;
	private DLFileVersionLocalService _dlFileVersionLocalService;
	private GroupLocalService _groupLocalService;
	private ImageLocalService _imageLocalService;

	@Reference
	private JSONFactory _jsonFactory;

	@Reference
	private Portal _portal;

	@Reference
	private SyncHelper _syncHelper;

	private UserLocalService _userLocalService;

	@Reference
	private ZipWriterFactory _zipWriterFactory;

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy