blob: 2da38f2669a3de6dd95612b386fabcc1f2243174 [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;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
import javax.jcr.RepositoryException;
import org.apache.jackrabbit.util.Text;
import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
import org.apache.jackrabbit.vault.fs.io.Archive;
import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
import org.apache.jackrabbit.vault.fs.io.DocViewParser;
import org.apache.jackrabbit.vault.fs.io.DocViewParser.XmlParseException;
import org.apache.jackrabbit.vault.fs.io.DocViewParserHandler;
import org.apache.jackrabbit.vault.util.DocViewNode2;
import org.apache.jackrabbit.vault.util.PlatformNameFormat;
import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
import org.apache.sling.feature.cpconverter.ConverterException;
import org.apache.sling.feature.cpconverter.index.IndexDefinitions;
import org.apache.sling.feature.cpconverter.index.IndexManager;
import org.apache.sling.feature.cpconverter.index.SimpleNamespaceResolver;
import org.jetbrains.annotations.NotNull;
import org.xml.sax.InputSource;
/**
* Handler for Jackrabbit Oak index definitions
*
* <p>This implementation scans content packages for entries stored under {@code /oak:index}
* and exposes them to the {@link IndexManager} for further processing.
*
*/
public class IndexDefinitionsEntryHandler extends AbstractRegexEntryHandler {
private static final String[] EXCLUDED_EXTENSIONS = new String[]{
"vlt",
"gitignore"
};
private static final String PATH_PATTERN = "" +
"/jcr_root" + // jcr_root dir
"(.*/?)/" + // optional path segment
PlatformNameFormat.getPlatformName(IndexDefinitions.OAK_INDEX_NAME) +
"(.*/?)" + // additional path segments
"/(.*?)\\.(?!(" + //excluding extensions
String.join("|", EXCLUDED_EXTENSIONS) +
")$)[^.]+$"; // match everything else
private final class IndexDefinitionsParserHandler implements DocViewParserHandler {
private final WorkspaceFilter filter;
private IndexDefinitions definitions;
public IndexDefinitionsParserHandler(WorkspaceFilter filter, IndexDefinitions definitions) {
this.filter = filter;
this.definitions = definitions;
}
@Override
public void startDocViewNode(@NotNull String nodePath, @NotNull DocViewNode2 docViewNode,
@NotNull Optional<DocViewNode2> parentDocViewNode, int line, int column)
throws IOException, RepositoryException {
if ( nodePath.contains(IndexDefinitions.OAK_INDEX_PATH) && filter.contains(nodePath) ) {
definitions.addNode(Text.getRelativeParent(nodePath, 1), docViewNode);
}
}
@Override
public void endDocViewNode(@NotNull String nodePath, @NotNull DocViewNode2 docViewNode,
@NotNull Optional<DocViewNode2> parentDocViewNode, int line, int column)
throws IOException, RepositoryException {
// nothing to do
}
@Override
public void startPrefixMapping(String prefix, String uri) {
definitions.registerPrefixMapping(prefix, uri);
}
}
public IndexDefinitionsEntryHandler() {
super(PATH_PATTERN);
}
@Override
public void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry,
@NotNull ContentPackage2FeatureModelConverter converter, String runMode) throws IOException, ConverterException {
IndexManager indexManager = converter.getIndexManager();
if ( indexManager == null ) {
logger.info("{} not present, will skip index definition extraction", IndexManager.class.getName());
} else {
try (InputStream is = archive.openInputStream(entry)) {
String platformPath = path.replaceAll("^/jcr_root", "")
.replaceAll("/\\.content\\.xml$", "")
.replace(".dir", "");
String repositoryPath = PlatformNameFormat.getRepositoryPath(platformPath);
InputSource inputSource = new InputSource(is);
boolean isDocView = false;
// DocViewParser.isDocView closes the input stream it is passed
try ( InputStream isCheck = archive.openInputStream(entry) ) {
isDocView = DocViewParser.isDocView(new InputSource(isCheck));
}
if ( isDocView ) {
DocViewParser parser = new DocViewParser(new SimpleNamespaceResolver());
IndexDefinitionsParserHandler handler = new IndexDefinitionsParserHandler(archive.getMetaInf().getFilter(), indexManager.getIndexes());
parser.parse(repositoryPath, inputSource, handler);
} else {
// binary file, should we attach?
if ( archive.getMetaInf().getFilter().contains(repositoryPath)) {
indexManager.getIndexes().registerBinary(repositoryPath, is);
}
}
} catch (XmlParseException e) {
throw new ConverterException("Failed parsing the index definitions", e);
}
}
converter.getMainPackageAssembler().addEntry(path, archive, entry);
}
}