/**
* 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.document.library.document.conversion.internal;
import com.artofsolving.jodconverter.DefaultDocumentFormatRegistry;
import com.artofsolving.jodconverter.DocumentConverter;
import com.artofsolving.jodconverter.DocumentFormat;
import com.artofsolving.jodconverter.DocumentFormatRegistry;
import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter;
import com.artofsolving.jodconverter.openoffice.converter.StreamOpenOfficeDocumentConverter;
import com.liferay.document.library.document.conversion.configuration.OpenOfficeConfiguration;
import com.liferay.document.library.kernel.document.conversion.DocumentConversion;
import com.liferay.portal.configuration.metatype.bnd.util.ConfigurableUtil;
import com.liferay.portal.kernel.configuration.Filter;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.SortedArrayList;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.SystemProperties;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.util.PropsUtil;
import com.liferay.portal.util.PropsValues;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
/**
* @author Bruno Farache
* @author Alexander Chow
*/
@Component(
configurationPid = "com.liferay.document.library.document.conversion.configuration.OpenOfficeConfiguration",
immediate = true, service = DocumentConversion.class
)
public class DocumentConversionImpl implements DocumentConversion {
@Override
public File convert(
String id, InputStream inputStream, String sourceExtension,
String targetExtension)
throws IOException {
if (!isEnabled()) {
return null;
}
sourceExtension = _fixExtension(sourceExtension);
targetExtension = _fixExtension(targetExtension);
_validate(targetExtension, id);
String fileName = getFilePath(id, targetExtension);
File file = new File(fileName);
if (_openOfficeConfiguration.cacheEnabled() && file.exists()) {
return file;
}
DocumentFormatRegistry documentFormatRegistry =
new DefaultDocumentFormatRegistry();
DocumentFormat inputDocumentFormat =
documentFormatRegistry.getFormatByFileExtension(sourceExtension);
DocumentFormat outputDocumentFormat =
documentFormatRegistry.getFormatByFileExtension(targetExtension);
if (inputDocumentFormat == null) {
throw new SystemException(
"Conversion is not supported from ." + sourceExtension);
}
else if (!inputDocumentFormat.isImportable()) {
throw new SystemException(
"Conversion is not supported from " +
inputDocumentFormat.getName());
}
else if (outputDocumentFormat == null) {
throw new SystemException(
"Conversion is not supported from " +
inputDocumentFormat.getName() + " to ." + targetExtension);
}
else if (!inputDocumentFormat.isExportableTo(outputDocumentFormat)) {
throw new SystemException(
"Conversion is not supported from " +
inputDocumentFormat.getName() + " to " +
outputDocumentFormat.getName());
}
UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
new UnsyncByteArrayOutputStream();
DocumentConverter documentConverter = _getDocumentConverter();
documentConverter.convert(
inputStream, inputDocumentFormat, unsyncByteArrayOutputStream,
outputDocumentFormat);
FileUtil.write(
file, unsyncByteArrayOutputStream.unsafeGetByteArray(), 0,
unsyncByteArrayOutputStream.size());
return file;
}
@Override
public void disconnect() {
if (_openOfficeConnection != null) {
_openOfficeConnection.disconnect();
}
}
@Override
public String[] getConversions(String extension) {
extension = _fixExtension(extension);
String[] conversions = _conversionsMap.get(extension);
if (conversions == null) {
conversions = _DEFAULT_CONVERSIONS;
}
else {
if (ArrayUtil.contains(conversions, extension)) {
List<String> conversionsList = new ArrayList<>();
for (int i = 0; i < conversions.length; i++) {
String conversion = conversions[i];
if (!conversion.equals(extension)) {
conversionsList.add(conversion);
}
}
conversions = conversionsList.toArray(
new String[conversionsList.size()]);
}
}
return conversions;
}
@Override
public String getFilePath(String id, String targetExtension) {
StringBundler sb = new StringBundler(5);
sb.append(SystemProperties.get(SystemProperties.TMP_DIR));
sb.append("/liferay/document_conversion/");
sb.append(id);
sb.append(StringPool.PERIOD);
sb.append(targetExtension);
return sb.toString();
}
@Override
public boolean isComparableVersion(String extension) {
boolean enabled = false;
String periodAndExtension = StringPool.PERIOD.concat(extension);
for (int i = 0; i < _COMPARABLE_FILE_EXTENSIONS.length; i++) {
if (StringPool.STAR.equals(_COMPARABLE_FILE_EXTENSIONS[i]) ||
periodAndExtension.equals(_COMPARABLE_FILE_EXTENSIONS[i])) {
enabled = true;
break;
}
}
if (!enabled) {
return false;
}
if (extension.equals("css") || extension.equals("htm") ||
extension.equals("html") || extension.equals("js") ||
extension.equals("txt") || extension.equals("xml")) {
return true;
}
try {
if (isEnabled() && isConvertBeforeCompare(extension)) {
return true;
}
}
catch (Exception e) {
_log.error(e, e);
}
return false;
}
@Override
public boolean isConvertBeforeCompare(String extension) {
if (extension.equals("txt")) {
return false;
}
String[] conversions = getConversions(extension);
for (int i = 0; i < conversions.length; i++) {
if (conversions[i].equals("txt")) {
return true;
}
}
return false;
}
@Override
public boolean isEnabled() {
return _openOfficeConfiguration.serverEnabled();
}
@Activate
@Modified
protected void activate(Map<String, Object> properties) {
_openOfficeConfiguration = ConfigurableUtil.createConfigurable(
OpenOfficeConfiguration.class, properties);
_populateConversionsMap("drawing");
_populateConversionsMap("presentation");
_populateConversionsMap("spreadsheet");
_populateConversionsMap("text");
}
private String _fixExtension(String extension) {
if (extension.equals("htm")) {
extension = "html";
}
return extension;
}
private DocumentConverter _getDocumentConverter() {
if ((_openOfficeConnection != null) && (_documentConverter != null)) {
return _documentConverter;
}
String host = _openOfficeConfiguration.serverHost();
int port = _openOfficeConfiguration.serverPort();
if (_isRemoteOpenOfficeHost(host)) {
_openOfficeConnection = new SocketOpenOfficeConnection(host, port);
_documentConverter = new StreamOpenOfficeDocumentConverter(
_openOfficeConnection);
}
else {
_openOfficeConnection = new SocketOpenOfficeConnection(port);
_documentConverter = new OpenOfficeDocumentConverter(
_openOfficeConnection);
}
return _documentConverter;
}
private boolean _isRemoteOpenOfficeHost(String host) {
if (Validator.isNotNull(host) && !host.equals(_LOCALHOST_IP) &&
!host.startsWith(_LOCALHOST)) {
return true;
}
else {
return false;
}
}
private void _populateConversionsMap(String documentFamily) {
Filter filter = new Filter(documentFamily);
DocumentFormatRegistry documentFormatRegistry =
new DefaultDocumentFormatRegistry();
String[] sourceExtensions = PropsUtil.getArray(
PropsKeys.OPENOFFICE_CONVERSION_SOURCE_EXTENSIONS, filter);
String[] targetExtensions = PropsUtil.getArray(
PropsKeys.OPENOFFICE_CONVERSION_TARGET_EXTENSIONS, filter);
for (String sourceExtension : sourceExtensions) {
List<String> conversions = new SortedArrayList<>();
DocumentFormat sourceDocumentFormat =
documentFormatRegistry.getFormatByFileExtension(
sourceExtension);
if (sourceDocumentFormat == null) {
if (_log.isWarnEnabled()) {
_log.warn("Invalid source extension " + sourceExtension);
}
continue;
}
for (String targetExtension : targetExtensions) {
DocumentFormat targetDocumentFormat =
documentFormatRegistry.getFormatByFileExtension(
targetExtension);
if (targetDocumentFormat == null) {
if (_log.isWarnEnabled()) {
_log.warn(
"Invalid target extension " + targetDocumentFormat);
}
continue;
}
if (sourceDocumentFormat.isExportableTo(targetDocumentFormat)) {
conversions.add(targetExtension);
}
}
if (conversions.isEmpty()) {
if (_log.isInfoEnabled()) {
_log.info(
"There are no conversions supported from " +
sourceExtension);
}
}
else {
if (_log.isInfoEnabled()) {
_log.info(
"Conversions supported from " + sourceExtension +
" to " + conversions);
}
_conversionsMap.put(
sourceExtension,
conversions.toArray(new String[conversions.size()]));
}
}
}
private void _validate(String targetExtension, String id) {
if (!Validator.isFileExtension(targetExtension)) {
throw new SystemException("Invalid extension: " + targetExtension);
}
if (!Validator.isFileName(id)) {
throw new SystemException("Invalid file name: " + id);
}
}
private static final String[] _COMPARABLE_FILE_EXTENSIONS =
PropsValues.DL_COMPARABLE_FILE_EXTENSIONS;
private static final String[] _DEFAULT_CONVERSIONS = new String[0];
private static final String _LOCALHOST = "localhost";
private static final String _LOCALHOST_IP = "127.0.0.1";
private static final Log _log = LogFactoryUtil.getLog(
DocumentConversionImpl.class);
private final Map<String, String[]> _conversionsMap = new HashMap<>();
private DocumentConverter _documentConverter;
private volatile OpenOfficeConfiguration _openOfficeConfiguration;
private OpenOfficeConnection _openOfficeConnection;
}