blob: 2684d5df7496fddf1c9b5deb4dd3433e12a955b2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.sling.feature.cpconverter.handlers.slinginitialcontent;
import static org.apache.sling.feature.cpconverter.shared.ConverterConstants.SLASH;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Set;
import javax.jcr.RepositoryException;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.util.Text;
import org.apache.jackrabbit.vault.fs.io.Archive;
import org.apache.jackrabbit.vault.util.PlatformNameFormat;
import org.apache.sling.feature.cpconverter.ConverterException;
import org.apache.sling.feature.cpconverter.vltpkg.SingleFileArchive;
import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
import org.apache.sling.jcr.contentloader.ContentReader;
import org.apache.sling.jcr.contentloader.PathEntry;
import org.jetbrains.annotations.NotNull;
/**
* Handles the bundle sling initial content extraction on the jarEntry level.
*/
class BundleSlingInitialContentJarEntryExtractor {
private final AssemblerProvider assemblerProvider;
private final ContentReaderProvider contentReaderProvider;
private final ParentFolderRepoInitHandler parentFolderRepoInitHandler;
BundleSlingInitialContentJarEntryExtractor(@NotNull AssemblerProvider assemblerProvider,
@NotNull ContentReaderProvider contentReaderProvider,
@NotNull ParentFolderRepoInitHandler parentFolderRepoInitHandler) {
this.assemblerProvider = assemblerProvider;
this.contentReaderProvider = contentReaderProvider;
this.parentFolderRepoInitHandler = parentFolderRepoInitHandler;
}
/**
* Extract slingInitialContentBundleEntryMetaData and add it to the assembler
*
* @param context BundleSlingInitialContentExtractContext
* @param slingInitialContentBundleEntryMetaData SlingInitialContentBundleEntryMetaData
* @param collectedSlingInitialContentBundleEntries complete set of all SlingInitialContentBundleEntryMetaData for the bundle
* @throws IOException
* @throws ConverterException
*/
void extractAndAddToAssembler(@NotNull BundleSlingInitialContentExtractContext context,
@NotNull SlingInitialContentBundleEntryMetaData slingInitialContentBundleEntryMetaData,
@NotNull Set<SlingInitialContentBundleEntryMetaData> collectedSlingInitialContentBundleEntries) throws IOException, ConverterException {
String repositoryPath = slingInitialContentBundleEntryMetaData.getRepositoryPath();
File file = slingInitialContentBundleEntryMetaData.getTargetFile();
PathEntry pathEntryValue = slingInitialContentBundleEntryMetaData.getPathEntry();
// all entry paths used by entry handlers start with "/"
String contentPackageEntryPath = SLASH + org.apache.jackrabbit.vault.util.Constants.ROOT_DIR + PlatformNameFormat.getPlatformPath(repositoryPath);
Path tmpDocViewInputFile = null;
try (InputStream bundleFileInputStream = new FileInputStream(file)) {
VaultPackageAssembler packageAssembler = assemblerProvider.initPackageAssemblerForPath(context, repositoryPath, pathEntryValue);
final ContentReader contentReader = contentReaderProvider.getContentReaderForEntry(file, pathEntryValue);
if (contentReader != null) {
// convert to docview xml
tmpDocViewInputFile = Files.createTempFile(context.getConverter().getTempDirectory().toPath(), "docview", ".xml");
try (OutputStream docViewOutput = Files.newOutputStream(tmpDocViewInputFile, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
repositoryPath = FilenameUtils.removeExtension(repositoryPath);
boolean isFileDescriptorEntry = isFileDescriptor(collectedSlingInitialContentBundleEntries, contentPackageEntryPath);
VaultContentXMLContentCreator contentCreator = new VaultContentXMLContentCreator(StringUtils.substringBeforeLast(repositoryPath, "/"), docViewOutput, context.getNamespaceRegistry(), packageAssembler, isFileDescriptorEntry);
if (file.getName().endsWith(".xml")) {
contentCreator.setIsXmlProcessed();
}
contentReader.parse(file.toURI().toURL(), contentCreator);
contentPackageEntryPath = new ContentPackageEntryPathComputer(collectedSlingInitialContentBundleEntries, contentPackageEntryPath, contentCreator).compute();
contentCreator.finish();
} catch (IOException e) {
throw new IOException("Can not parse " + file, e);
} catch (RepositoryException e) {
throw new IOException("Can not convert " + file + " to enhanced DocView format", e);
}
// remap CND files to make sure they are picked up by the NodeTypesEntryHandler
if (context.getNamespaceRegistry().getRegisteredCndSystemIds().contains(file.getName())) {
contentPackageEntryPath = "/META-INF/vault/" + Text.getName(file.getName()) + ".cnd";
}
}
try (Archive virtualArchive = SingleFileArchive.fromPathOrInputStream(tmpDocViewInputFile, bundleFileInputStream,
() -> Files.createTempFile(context.getConverter().getTempDirectory().toPath(), "initial-content", Text.getName(file.getName())), contentPackageEntryPath)) {
// in which content package should this end up?
if (tmpDocViewInputFile != null) {
packageAssembler.addEntry(contentPackageEntryPath, tmpDocViewInputFile.toFile());
} else {
packageAssembler.addEntry(contentPackageEntryPath, bundleFileInputStream);
}
parentFolderRepoInitHandler.addParentsForPath(contentPackageEntryPath);
}
} finally {
if (tmpDocViewInputFile != null) {
Files.delete(tmpDocViewInputFile);
}
}
}
private boolean isFileDescriptor(@NotNull Set<SlingInitialContentBundleEntryMetaData> bundleEntries, @NotNull final String contentPackageEntryPath) {
//sometimes we are dealing with double extensions (.json.xml)
String recomputedContentPackageEntryPath = FilenameUtils.removeExtension(contentPackageEntryPath);
final String checkIfRecomputedPathCandidate = StringUtils.removeStart(recomputedContentPackageEntryPath, "/jcr_root");
return bundleEntries.stream().anyMatch(bundleEntry -> StringUtils.equals(checkIfRecomputedPathCandidate, bundleEntry.getRepositoryPath()));
}
}