/**
* 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.knowledge.base.internal.importer;
import com.liferay.knowledge.base.configuration.KBGroupServiceConfiguration;
import com.liferay.knowledge.base.exception.KBArticleImportException;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.module.configuration.ConfigurationProvider;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.zip.ZipReader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* @author Adolfo PĂ©rez
*/
@Component(service = KBArchiveFactory.class)
public class KBArchiveFactory {
public KBArchive createKBArchive(long groupId, ZipReader zipReader)
throws PortalException {
List<String> entries = zipReader.getEntries();
if (entries == null) {
throw new KBArticleImportException(
"The uploaded file is not a ZIP archive or it is corrupted");
}
KBGroupServiceConfiguration kbGroupServiceConfiguration =
_configurationProvider.getGroupConfiguration(
KBGroupServiceConfiguration.class, groupId);
Collections.sort(entries);
KBArchiveState kbArchiveState = new KBArchiveState(zipReader);
for (String entry : entries) {
String[] articleExtensions =
kbGroupServiceConfiguration.markdownImporterArticleExtensions();
if (!ArrayUtil.exists(articleExtensions, entry::endsWith)) {
continue;
}
Path entryPath = Paths.get(entry);
Path entryParentPath = entryPath.getParent();
kbArchiveState.setCurrentFolder(entryParentPath);
Path entryFileNamePath = entryPath.getFileName();
String markdownImporterArticleIntro =
kbGroupServiceConfiguration.markdownImporterArticleIntro();
String entryFileName = entryFileNamePath.toString();
if (entryFileName.endsWith(markdownImporterArticleIntro)) {
kbArchiveState.setCurrentFolderIntroFile(entryPath);
}
else {
kbArchiveState.addCurrentFolderFile(entryPath);
}
}
return new KBArchiveImpl(kbArchiveState.getFolders());
}
@Reference(unbind = "-")
public void setConfigurationProvider(
ConfigurationProvider configurationProvider) {
_configurationProvider = configurationProvider;
}
private ConfigurationProvider _configurationProvider;
private static final class FileImpl implements KBArchive.File {
public FileImpl(String name, ZipReader zipReader) {
_name = name;
_zipReader = zipReader;
}
@Override
public String getContent() {
return _zipReader.getEntryAsString(getName());
}
@Override
public String getName() {
return _name;
}
private final String _name;
private final ZipReader _zipReader;
}
private static final class FolderImpl implements KBArchive.Folder {
public FolderImpl(
String name, KBArchive.Folder parentFolder,
KBArchive.File introFile, Collection<KBArchive.File> files) {
_name = name;
_parentFolder = parentFolder;
_introFile = introFile;
_files = files;
}
@Override
public Collection<KBArchive.File> getFiles() {
return _files;
}
@Override
public KBArchive.File getIntroFile() {
return _introFile;
}
@Override
public String getName() {
return _name;
}
@Override
public KBArchive.File getParentFolderIntroFile() {
if (_parentFolder == null) {
return null;
}
return _parentFolder.getIntroFile();
}
private final Collection<KBArchive.File> _files;
private final KBArchive.File _introFile;
private final String _name;
private final KBArchive.Folder _parentFolder;
}
private static final class KBArchiveImpl implements KBArchive {
public KBArchiveImpl(Collection<KBArchive.Folder> folders) {
_folders = folders;
}
@Override
public Collection<KBArchive.Folder> getFolders() {
return _folders;
}
private final Collection<KBArchive.Folder> _folders;
}
private static final class KBArchiveState {
public KBArchiveState(ZipReader zipReader) {
_zipReader = zipReader;
}
public void addCurrentFolderFile(Path path) {
_currentFolderFiles.add(new FileImpl(path.toString(), _zipReader));
}
public Collection<KBArchive.Folder> getFolders() {
_saveCurrentFolderState();
return _folders.values();
}
public void setCurrentFolder(Path folderPath) {
if (folderPath == null) {
folderPath = _ROOT_FOLDER_PATH;
}
if (folderPath.equals(_currentFolderPath)) {
return;
}
_saveCurrentFolderState();
_restoreFolderState(folderPath);
}
public void setCurrentFolderIntroFile(Path path) {
_currentFolderIntroFile = new FileImpl(path.toString(), _zipReader);
}
private void _restoreFolderState(Path folderPath) {
_currentFolderPath = folderPath;
KBArchive.Folder folder = _folders.get(folderPath);
if (folder != null) {
_currentFolderIntroFile = folder.getIntroFile();
_currentFolderFiles = folder.getFiles();
}
else {
_currentFolderIntroFile = null;
_currentFolderFiles = new ArrayList<>();
}
}
private void _saveCurrentFolderState() {
if ((_currentFolderPath == null) ||
((_currentFolderIntroFile == null) &&
_currentFolderFiles.isEmpty())) {
return;
}
Path currentFolderParentPath = _currentFolderPath.getParent();
KBArchive.Folder parentFolder = null;
if (currentFolderParentPath != null) {
parentFolder = _folders.get(currentFolderParentPath);
}
KBArchive.Folder folder = new FolderImpl(
_currentFolderPath.toString(), parentFolder,
_currentFolderIntroFile, _currentFolderFiles);
_folders.put(_currentFolderPath, folder);
}
private static final Path _ROOT_FOLDER_PATH = Paths.get(
StringPool.SLASH);
private Collection<KBArchive.File> _currentFolderFiles;
private KBArchive.File _currentFolderIntroFile;
private Path _currentFolderPath;
private final Map<Path, KBArchive.Folder> _folders = new TreeMap<>();
private final ZipReader _zipReader;
}
}