You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2023/05/08 14:22:21 UTC
[sling-org-apache-sling-feature-cpconverter] 01/01: Revert "SLING-11421 Use FileVault serialization classes for generating enhanced (#161)"
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch issue/SLING-11865-with-revert
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-cpconverter.git
commit 3c0cb4101580e61971958e5a57a6f1ce9cf34889
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Mon May 8 16:22:05 2023 +0200
Revert "SLING-11421 Use FileVault serialization classes for generating enhanced (#161)"
This reverts commit 084e751fb5c170eeee9b701ceee9cee1cfb27aac.
---
pom.xml | 15 +-
...BundleSlingInitialContentJarEntryExtractor.java | 12 +-
.../ContentPackageEntryPathComputer.java | 74 ++++++
.../slinginitialcontent/DocViewTreeNode.java | 87 ------
.../SlingInitialContentBundleEntryMetaData.java | 26 +-
...InitialContentBundleEntryMetaDataCollector.java | 6 +-
.../VaultContentXMLContentCreator.java | 293 ++++++++-------------
.../XMLNodeToXMLFileWriter.java | 111 ++++++++
.../slinginitialcontent/xmlbuffer/XMLNode.java | 158 +++++++++++
.../createpath/CreatePathSegmentProcessor.java | 2 +-
.../BundleEntryHandleSlingInitialContentTest.java | 86 +++---
...aem632-project.core-0.0.1-SNAPSHOT-escaping.jar | Bin 16178 -> 0 bytes
.../handlers/bundle-entry-xmls/11mumbojumbo.xml | 5 +-
.../handlers/bundle-entry-xmls/homepage.xml | 4 +-
.../bundle-entry-xmls/include-redirectStatus.xml | 26 +-
.../handlers/bundle-entry-xmls/nodeName.xml | 5 +-
.../cpconverter/handlers/bundle-entry-xmls/xyz.xml | 5 +-
.../handlers/escaping-test/.content.xml | 4 -
.../en.json.dir/.content.xml | 5 +-
19 files changed, 538 insertions(+), 386 deletions(-)
diff --git a/pom.xml b/pom.xml
index bbd539e..3e5ff31 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,7 +35,7 @@
<sling.java.version>8</sling.java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<picocli.version>3.6.0</picocli.version>
- <org.apache.jackrabbit.vault.version>3.6.8</org.apache.jackrabbit.vault.version>
+ <org.apache.jackrabbit.vault.version>3.6.0</org.apache.jackrabbit.vault.version>
<jackrabbit-api.version>1.42.0</jackrabbit-api.version>
<jackrabbit-spi-commons.version>2.20.4</jackrabbit-spi-commons.version>
<license-maven-plugin.version>1.16</license-maven-plugin.version>
@@ -115,6 +115,12 @@
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>stax-utils</groupId>
+ <artifactId>stax-utils</artifactId>
+ <version>snapshot-20040917</version>
+ <scope>compile</scope>
+ </dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-spi-commons</artifactId>
@@ -132,12 +138,6 @@
<version>2.11.0</version>
<scope>compile</scope>
</dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- <version>3.6</version>
- <scope>compile</scope>
- </dependency>
<!--
| Sling Feature Model libraries
@@ -379,7 +379,6 @@
<exclude>src/main/resources/META-INF/services/org.apache.sling.feature.cpconverter.handlers.EntryHandler</exclude>
<exclude>src/main/legal/NOTICE-with-deps</exclude>
<exclude>src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/**</exclude>
- <exclude>src/test/resources/org/apache/sling/feature/cpconverter/handlers/escaping-test/**</exclude>
<exclude>src/test/resources/org/apache/sling/feature/cpconverter/handlers/i18n-jsonfile-xml-descriptor-test/**</exclude>
</excludes>
</configuration>
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/BundleSlingInitialContentJarEntryExtractor.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/BundleSlingInitialContentJarEntryExtractor.java
index ccd0e09..2684d5d 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/BundleSlingInitialContentJarEntryExtractor.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/BundleSlingInitialContentJarEntryExtractor.java
@@ -73,7 +73,7 @@ class BundleSlingInitialContentJarEntryExtractor {
@NotNull Set<SlingInitialContentBundleEntryMetaData> collectedSlingInitialContentBundleEntries) throws IOException, ConverterException {
String repositoryPath = slingInitialContentBundleEntryMetaData.getRepositoryPath();
- File file = slingInitialContentBundleEntryMetaData.getSourceFile();
+ 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);
@@ -92,12 +92,16 @@ class BundleSlingInitialContentJarEntryExtractor {
repositoryPath = FilenameUtils.removeExtension(repositoryPath);
boolean isFileDescriptorEntry = isFileDescriptor(collectedSlingInitialContentBundleEntries, contentPackageEntryPath);
- VaultContentXMLContentCreator contentCreator = new VaultContentXMLContentCreator(repositoryPath, docViewOutput, context.getNamespaceRegistry(), packageAssembler, isFileDescriptorEntry);
+ 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);
- // finish is not always called through the ContentReader unfortunately
+ contentPackageEntryPath = new ContentPackageEntryPathComputer(collectedSlingInitialContentBundleEntries, contentPackageEntryPath, contentCreator).compute();
contentCreator.finish();
- contentPackageEntryPath = contentCreator.getContentPackageEntryPath();
} catch (IOException e) {
throw new IOException("Can not parse " + file, e);
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/ContentPackageEntryPathComputer.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/ContentPackageEntryPathComputer.java
new file mode 100644
index 0000000..96ab646
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/ContentPackageEntryPathComputer.java
@@ -0,0 +1,74 @@
+/*
+ * 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 org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+
+import static org.apache.jackrabbit.vault.util.Constants.DOT_CONTENT_XML;
+import static org.apache.sling.feature.cpconverter.shared.ConverterConstants.SLASH;
+
+/**
+ * Performs re-computation of the ContentPackagePath of the bundle entry (Sling Initial Content)
+ */
+class ContentPackageEntryPathComputer {
+
+ private final Set<SlingInitialContentBundleEntryMetaData> bundleEntries;
+ private final String contentPackageEntryPath;
+ private final VaultContentXMLContentCreator contentCreator;
+
+ ContentPackageEntryPathComputer(@NotNull Set<SlingInitialContentBundleEntryMetaData> bundleEntries,
+ @NotNull final String contentPackageEntryPath,
+ @NotNull VaultContentXMLContentCreator contentCreator) {
+ this.bundleEntries = bundleEntries;
+ this.contentPackageEntryPath = contentPackageEntryPath;
+ this.contentCreator = contentCreator;
+ }
+
+ @NotNull
+ String compute() {
+
+ String recomputedContentPackageEntryPath = FilenameUtils.removeExtension(contentPackageEntryPath);
+
+ // this covers the case of having a primary node name defined in the xml/json descriptor itself.
+ // if this is set, we need to use it in the path.
+ if (StringUtils.isNotBlank(contentCreator.getPrimaryNodeName())) {
+ //custom node name
+ recomputedContentPackageEntryPath = StringUtils.substringBeforeLast(recomputedContentPackageEntryPath, SLASH);
+ recomputedContentPackageEntryPath = recomputedContentPackageEntryPath + SLASH + contentCreator.getPrimaryNodeName();
+ }
+
+ final String checkIfRecomputedPathCandidate = StringUtils.removeStart(recomputedContentPackageEntryPath, "/jcr_root");
+ // check if the resulting candidate matches one of the repositoryPaths in the bundle entries we have.
+ // for example /apps/testJsonFile.json.xml (descriptor entry)
+ // will match /apps/testJsonFile.json (file entry)
+ if (bundleEntries.stream().anyMatch(bundleEntry -> StringUtils.equals(checkIfRecomputedPathCandidate, bundleEntry.getRepositoryPath()))) {
+ //we are dealing with a file descriptor here
+ recomputedContentPackageEntryPath = recomputedContentPackageEntryPath + ".dir/" + DOT_CONTENT_XML;
+ } else {
+ // in this case we are dealing with a folder descriptor. for example:
+ // /apps/testJsonFolder.json
+ // we want it to end up in the following format: /apps/testJsonFolder/.content.xml in our assembler.
+ recomputedContentPackageEntryPath = recomputedContentPackageEntryPath + SLASH + DOT_CONTENT_XML;
+ }
+
+ return recomputedContentPackageEntryPath;
+ }
+}
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/DocViewTreeNode.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/DocViewTreeNode.java
deleted file mode 100644
index 1676683..0000000
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/DocViewTreeNode.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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 java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.jcr.NamespaceException;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-
-import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
-import org.apache.jackrabbit.spi.commons.name.NameConstants;
-import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
-import org.apache.jackrabbit.vault.util.DocViewNode2;
-import org.apache.jackrabbit.vault.util.DocViewProperty2;
-
-/**
- * Represents a serializable docview node inside a tree hierarchy.
- *
- */
-public class DocViewTreeNode {
-
- private final List<DocViewTreeNode> children;
- private final Name name;
- private final String parentPath;
- private final Collection<DocViewProperty2> properties;
-
- public DocViewTreeNode(String parentPath, Name name, Collection<DocViewProperty2> properties) {
- children = new LinkedList<>();
- this.name = name;
- this.properties = properties;
- this.parentPath = parentPath;
- }
-
- public void addChild(DocViewTreeNode child) {
- children.add(child);
- }
-
- void write(XMLStreamWriter writer, NamespaceResolver nsResolver) throws NamespaceException, XMLStreamException {
- write(writer, nsResolver, Collections.emptyList());
- }
-
- public void write(XMLStreamWriter writer, NamespaceResolver nsResolver, Iterable<String> nsPrefixes) throws NamespaceException, XMLStreamException {
- DocViewNode2 docViewNode = new DocViewNode2(name, properties);
- docViewNode.writeStart(writer, nsResolver, nsPrefixes);
- for (DocViewTreeNode child : children) {
- child.write(writer, nsResolver);
- }
- DocViewNode2.writeEnd(writer);
- }
-
- public Collection<DocViewProperty2> getProperties() {
- return properties;
- }
-
- /**
- *
- * @param nameResolver
- * @return the absolute JCR path (in qualified form) of the node represented by this class
- * @throws NamespaceException
- */
- public String getPath(NameResolver nameResolver) throws NamespaceException {
- if (NameConstants.JCR_ROOT.equals(name)) {
- return parentPath;
- } else {
- return parentPath + "/" + nameResolver.getJCRName(name);
- }
- }
-}
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/SlingInitialContentBundleEntryMetaData.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/SlingInitialContentBundleEntryMetaData.java
index 33a345e..d8b15be 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/SlingInitialContentBundleEntryMetaData.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/SlingInitialContentBundleEntryMetaData.java
@@ -23,45 +23,33 @@ import java.io.File;
import java.util.Objects;
/**
- * Holds Initial Content meta data for a single file
+ * Holds BundleEntry MetaData.
*/
class SlingInitialContentBundleEntryMetaData {
- private final File sourceFile;
+ private final File targetFile;
private final PathEntry pathEntry;
private final String repositoryPath;
SlingInitialContentBundleEntryMetaData(
- @NotNull File sourceFile,
+ @NotNull File targetFile,
@NotNull PathEntry pathEntry,
@NotNull String repositoryPath) {
- this.sourceFile = sourceFile;
+ this.targetFile = targetFile;
this.pathEntry = pathEntry;
this.repositoryPath = repositoryPath;
}
- /**
- *
- * @return the initial content file which is supposed to be installed to {@link #getRepositoryPath()}
- */
@NotNull
- File getSourceFile() {
- return sourceFile;
+ File getTargetFile() {
+ return targetFile;
}
- /**
- *
- * @return the path entry covering the file {@link #sourceFile} (maybe for a parent)
- */
@NotNull
PathEntry getPathEntry() {
return pathEntry;
}
- /**
- *
- * @return the absolute target repository root path of the initial content inside {@link #sourceFile}
- */
@NotNull
String getRepositoryPath() {
return repositoryPath;
@@ -77,7 +65,7 @@ class SlingInitialContentBundleEntryMetaData {
@Override
public int hashCode() {
- return Objects.hash(sourceFile, pathEntry, repositoryPath);
+ return Objects.hash(targetFile, pathEntry, repositoryPath);
}
@Override
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/SlingInitialContentBundleEntryMetaDataCollector.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/SlingInitialContentBundleEntryMetaDataCollector.java
index e8f85fd..152e46e 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/SlingInitialContentBundleEntryMetaDataCollector.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/SlingInitialContentBundleEntryMetaDataCollector.java
@@ -181,15 +181,15 @@ class SlingInitialContentBundleEntryMetaDataCollector {
@NotNull
private SlingInitialContentBundleEntryMetaData createSlingInitialContentBundleEntry(@NotNull BundleSlingInitialContentExtractContext context,
- @NotNull File sourceFile) throws UnsupportedEncodingException {
- final String entryName = StringUtils.replace(StringUtils.substringAfter(sourceFile.getPath(), basePath + File.separator), File.separator, ZIP_ENTRY_SEPARATOR);
+ @NotNull File targetFile) throws UnsupportedEncodingException {
+ final String entryName = StringUtils.replace(StringUtils.substringAfter(targetFile.getPath(), basePath + File.separator), File.separator, ZIP_ENTRY_SEPARATOR);
final PathEntry pathEntryValue = context.getPathEntryList().stream().filter(
pathEntry -> checkIfPathStartsWithOrIsEqual(pathEntry.getPath(), entryName, ZIP_ENTRY_SEPARATOR)
).findFirst().orElseThrow(NullPointerException::new);
final String target = pathEntryValue.getTarget();
// https://sling.apache.org/documentation/bundles/content-loading-jcr-contentloader.html#file-name-escaping
String repositoryPath = (target != null ? target : "/") + URLDecoder.decode(entryName.substring(pathEntryValue.getPath().length()), "UTF-8");
- return new SlingInitialContentBundleEntryMetaData(sourceFile, pathEntryValue, repositoryPath);
+ return new SlingInitialContentBundleEntryMetaData(targetFile, pathEntryValue, repositoryPath);
}
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/VaultContentXMLContentCreator.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/VaultContentXMLContentCreator.java
index b94eea7..8c92dfd 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/VaultContentXMLContentCreator.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/VaultContentXMLContentCreator.java
@@ -16,272 +16,189 @@
*/
package org.apache.sling.feature.cpconverter.handlers.slinginitialcontent;
-import static org.apache.sling.feature.cpconverter.shared.ConverterConstants.SLASH;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.math.BigDecimal;
-import java.time.ZoneOffset;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Queue;
-import java.util.Set;
-import java.util.TimeZone;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.jcr.NamespaceException;
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.ValueFactory;
-import javax.xml.stream.FactoryConfigurationError;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.JcrConstants;
-import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
-import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
-import org.apache.jackrabbit.spi.commons.name.NameConstants;
-import org.apache.jackrabbit.util.Text;
-import org.apache.jackrabbit.value.ValueFactoryImpl;
-import org.apache.jackrabbit.vault.fs.io.DocViewFormat;
-import org.apache.jackrabbit.vault.util.Constants;
-import org.apache.jackrabbit.vault.util.DocViewProperty2;
-import org.apache.jackrabbit.vault.util.PlatformNameFormat;
-import org.apache.jackrabbit.vault.util.xml.serialize.FormattingXmlStreamWriter;
+import org.apache.sling.feature.cpconverter.handlers.slinginitialcontent.xmlbuffer.XMLNode;
import org.apache.sling.feature.cpconverter.vltpkg.JcrNamespaceRegistry;
import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
import org.apache.sling.jcr.contentloader.ContentCreator;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.xml.stream.XMLStreamException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
/**
- * ContentCreator implementation to write FileVault enhanced DocView XML files (to be packaged into a VaultPackage)
+ * ContentCreator substitute to create valid XML files to be packaged into a VaultPackage to be installed later
*/
public class VaultContentXMLContentCreator implements ContentCreator {
private static final String ACL_NOT_SUPPORTED_MSG = "Sling Initial Content - ACL statements are not supported yet . SLING issue: https://issues.apache.org/jira/browse/SLING-11060";
+ private final String repositoryPath;
+ private final OutputStream targetOutputStream;
private final VaultPackageAssembler packageAssembler;
- private final Queue<DocViewTreeNode> currentNodeStack = Collections.asLifoQueue(new ArrayDeque<>());
+ private final LinkedList<XMLNode> parentNodePathStack = new LinkedList<>();
private final JcrNamespaceRegistry namespaceRegistry;
- private final NamePathResolver npResolver;
- private final XMLStreamWriter writer;
- private String rootPath;
+
private final boolean isFileDescriptorEntry;
- private boolean isFinished = false;
- private DocViewTreeNode rootNode = null;
+ private boolean isFirstElement = true;
+ private boolean finished = false;
+ private boolean xmlProcessed = false;
+ private String primaryNodeName;
+ private XMLNode currentNode;
VaultContentXMLContentCreator(@NotNull String repositoryPath,
@NotNull OutputStream targetOutputStream,
@NotNull JcrNamespaceRegistry namespaceRegistry,
@NotNull VaultPackageAssembler packageAssembler,
- boolean isFileDescriptorEntry) throws RepositoryException, FactoryConfigurationError {
+ boolean isFileDescriptorEntry) {
+ this.repositoryPath = repositoryPath;
+ this.targetOutputStream = targetOutputStream;
this.packageAssembler = packageAssembler;
this.namespaceRegistry = namespaceRegistry;
this.isFileDescriptorEntry = isFileDescriptorEntry;
- this.npResolver = new DefaultNamePathResolver((NamespaceRegistry)namespaceRegistry);
- try {
- writer = FormattingXmlStreamWriter.create(targetOutputStream, new DocViewFormat().getXmlOutputFormat());
- } catch (XMLStreamException e) {
- throw new RepositoryException("Cannot create XML Writer " + e, e);
- }
- rootPath = repositoryPath;
}
- /**
- * The absolute entry path inside the content package ZIP for the generated docview.xml
- * @throws NamespaceException
- */
- public String getContentPackageEntryPath() throws NamespaceException {
- String suffix;
- if (isFileDescriptorEntry) {
- // it is potentially https://jackrabbit.apache.org/filevault/vaultfs.html#extended-file-aggregates (and may have file name clashes otherwise with the binary file in the content package)
- suffix = ".dir" + "/" + Constants.DOT_CONTENT_XML;
- } else {
- suffix = "/" + Constants.DOT_CONTENT_XML;
- }
- return SLASH + org.apache.jackrabbit.vault.util.Constants.ROOT_DIR + PlatformNameFormat.getPlatformPath(rootNode.getPath(npResolver)) + suffix;
+ void setIsXmlProcessed() {
+ this.xmlProcessed = true;
}
@Override
public void createNode(String name, String primaryNodeType, String[] mixinNodeTypes) throws RepositoryException {
- final Name currentNodeName;
- if (rootNode == null) {
- currentNodeName = NameConstants.JCR_ROOT;
- if (StringUtils.isNotBlank(name)) {
- // adjust root path in case the first node has an explicit name
- rootPath = Text.getRelativeParent(rootPath, 1) + "/" + name;
- }
+
+ final String elementName;
+ final String jcrNodeName;
+ if (xmlProcessed && isFirstElement) {
+ elementName = "jcr:root";
+ primaryNodeName = name;
+ jcrNodeName = name;
+ isFirstElement = false;
+ } else if (StringUtils.isNotBlank(name)) {
+ elementName = getValidElementName(name);
+ jcrNodeName = name;
} else {
- currentNodeName = npResolver.getQName(name);
+ elementName = "jcr:root";
+ jcrNodeName = null;
}
- // if we are dealing with a descriptor file, we should use nt:file as default primaryType.
+
+ final String basePath;
+ if (parentNodePathStack.isEmpty()) {
+ basePath = repositoryPath;
+ } else {
+ StringBuilder basePathBuilder = new StringBuilder(repositoryPath);
+ for (Iterator<XMLNode> xmlNodeIterator = parentNodePathStack.descendingIterator(); xmlNodeIterator.hasNext(); ) {
+ XMLNode parent = xmlNodeIterator.next();
+ String parentJcrNodeName = parent.getJcrNodeName();
+ if (StringUtils.isNotBlank(parentJcrNodeName)) {
+ basePathBuilder.append("/");
+ basePathBuilder.append(parentJcrNodeName);
+ }
+ }
+ basePath = basePathBuilder.toString();
+ }
+
+ //if we are dealing with a descriptor file, we should use nt:file as default primaryType.
+
String defaultNtType = isFileDescriptorEntry ? JcrConstants.NT_FILE : JcrConstants.NT_UNSTRUCTURED;
String toUsePrimaryNodeType = StringUtils.isNotBlank(primaryNodeType) ? primaryNodeType : defaultNtType;
- List<DocViewProperty2> currentProperties = new ArrayList<>();
- currentProperties.add(new DocViewProperty2(NameConstants.JCR_PRIMARYTYPE, toUsePrimaryNodeType));
+ XMLNode intermediateNode = new XMLNode(packageAssembler, basePath, elementName, jcrNodeName, toUsePrimaryNodeType, mixinNodeTypes);
+ //add the created node to the correct parent if present
+ if (currentNode != null) {
+ currentNode.addChildNode(elementName, intermediateNode);
+ }
+ //switch the current node
+ currentNode = intermediateNode;
+
if (ArrayUtils.isNotEmpty(mixinNodeTypes)) {
- currentProperties.add(new DocViewProperty2(NameConstants.JCR_MIXINTYPES, Arrays.asList(mixinNodeTypes)));
+ currentNode.addProperty(JcrConstants.JCR_MIXINTYPES, "[" + String.join(",", mixinNodeTypes) + "]");
}
- final DocViewTreeNode newNode;
- if (rootNode == null) {
- newNode = new DocViewTreeNode(rootPath, currentNodeName, currentProperties);
- rootNode = newNode;
- } else {
- newNode = new DocViewTreeNode(rootNode.getPath(npResolver), currentNodeName, currentProperties);
- currentNodeStack.element().addChild(newNode);
+
+ parentNodePathStack.push(currentNode);
+ }
+
+ @NotNull
+ private static String getValidElementName(@NotNull String name) {
+ if (StringUtils.isNumeric(name.substring(0, 1))) {
+ return "_" + name;
}
- currentNodeStack.add(newNode);
+ return name;
+ }
+
+ @Nullable
+ public String getPrimaryNodeName() {
+ return primaryNodeName;
}
@Override
- public void finishNode() throws RepositoryException {
- this.currentNodeStack.remove();
+ public void finishNode() {
+ if (parentNodePathStack.size() > 1) {
+ this.parentNodePathStack.pop();
+ }
+ this.currentNode = this.parentNodePathStack.peek();
}
@Override
public void finish() throws RepositoryException {
- if (isFinished) {
+
+ if (finished) {
return;
}
- isFinished = true;
try {
- rootNode.write(writer, namespaceRegistry, Arrays.asList(namespaceRegistry.getPrefixes()));
- writer.close();
+ XMLNodeToXMLFileWriter writer = new XMLNodeToXMLFileWriter(currentNode, targetOutputStream, namespaceRegistry);
+ writer.write();
+ finished = true;
} catch (XMLStreamException e) {
- throw new RepositoryException("Cannot close XML writer " + e, e);
+ throw new RepositoryException(e);
}
}
+
@Override
public void createProperty(String name, int propertyType, String value) throws RepositoryException {
- // add explicit type due to https://issues.apache.org/jira/browse/JCRVLT-693
- currentNodeStack.peek().getProperties().add(new DocViewProperty2(npResolver.getQName(name), value, propertyType == PropertyType.UNDEFINED ? PropertyType.STRING : propertyType));
+ currentNode.addProperty(name, propertyType, value);
}
+
@Override
public void createProperty(String name, int propertyType, String[] values) throws RepositoryException {
- // add explicit type due to https://issues.apache.org/jira/browse/JCRVLT-693
- currentNodeStack.peek().getProperties().add(new DocViewProperty2(npResolver.getQName(name), Arrays.asList(values), propertyType == PropertyType.UNDEFINED ? PropertyType.STRING : propertyType));
+ currentNode.addProperty(name, propertyType, values);
}
+
@Override
public void createProperty(String name, Object value) throws RepositoryException {
- // store binaries outside of docview xml
- Value jcrValue = createValue(name, value, -1);
- DocViewProperty2 property = DocViewProperty2.fromValues(npResolver.getQName(name), new Value[] { jcrValue }, jcrValue.getType(), false, false, false);
- currentNodeStack.peek().getProperties().add(property);
+ currentNode.addProperty(name, value);
}
+
@Override
public void createProperty(String name, Object[] values) throws RepositoryException {
- try {
- AtomicInteger index = new AtomicInteger();
- Value[] jcrValues = Arrays.stream(values).map(v -> {
- try {
- return createValue(name,v, index.getAndIncrement());
- } catch (RepositoryException e) {
- throw new UncheckedRepositoryException(e);
- }
- }).toArray(Value[]::new);
- final int type;
- if (jcrValues.length == 0) {
- type = PropertyType.STRING;
- } else {
- type = jcrValues[0].getType();
- }
- DocViewProperty2 property = DocViewProperty2.fromValues(npResolver.getQName(name), jcrValues, type, true, false, false);
- currentNodeStack.peek().getProperties().add(property);
- } catch (UncheckedRepositoryException e) {
- throw e.getCause();
- }
- }
-
- static final class UncheckedRepositoryException extends RuntimeException {
-
- private static final long serialVersionUID = 1L;
-
- public UncheckedRepositoryException(RepositoryException e) {
- super(e);
- }
-
- @Override
- public synchronized RepositoryException getCause() {
- return (RepositoryException) super.getCause();
- }
- }
-
- private Value createValue(String name, Object value, int index) throws RepositoryException {
- ValueFactory valueFactory = ValueFactoryImpl.getInstance();
- final Value jcrValue;
- if (value instanceof String) {
- jcrValue = valueFactory.createValue((String)value);
- } else if (value instanceof Long) {
- jcrValue = valueFactory.createValue((long)value);
- } else if (value instanceof Double) {
- jcrValue = valueFactory.createValue((Double)value);
- } else if (value instanceof BigDecimal) {
- jcrValue = valueFactory.createValue((BigDecimal)value);
- } else if (value instanceof Date) {
- Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(ZoneOffset.UTC), Locale.ROOT);
- calendar.setTime((Date)value);
- jcrValue = valueFactory.createValue(calendar);
- } else if (value instanceof Calendar) {
- jcrValue = valueFactory.createValue((Calendar)value);
- } else if (value instanceof Boolean) {
- jcrValue = valueFactory.createValue((Boolean)value);
- } else if (value instanceof InputStream) {
- // binaries are always stored outside the docview xml (https://jackrabbit.apache.org/filevault/vaultfs.html#Binary_Properties)
- String binaryPropertyEntryName = PlatformNameFormat.getPlatformName(name) + ((index != -1) ? "[" + index + "]" : "") + ".binary";
- createBinary((InputStream)value, SLASH + binaryPropertyEntryName);
- jcrValue = valueFactory.createValue("", PropertyType.BINARY);
- } else {
- throw new UnsupportedOperationException("Unsupported value type " + value.getClass());
- }
- return jcrValue;
- }
-
- private void createBinary(InputStream value, String suffix) throws RepositoryException {
- // this is called inside the node of the child
- String path = org.apache.jackrabbit.vault.util.Constants.ROOT_DIR + PlatformNameFormat.getPlatformPath(currentNodeStack.peek().getPath(npResolver)) + suffix;
- try {
- // write binary directly (not during finish)
- packageAssembler.addEntry(path, value);
- } catch (IOException e) {
- throw new RepositoryException(e);
- }
+ currentNode.addProperty(name, values);
}
@Override
public void createFileAndResourceNode(String name, InputStream data, String mimeType, long lastModified) throws RepositoryException {
this.createNode(name, JcrConstants.NT_FILE, null);
- createBinary(data, ""); // binary must be created with the name of the nt:file root node
this.createNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE, null);
- final Date date;
// ensure sensible last modification date
- if (lastModified >= 0) {
- date = new Date(lastModified);
- } else {
- date = new Date();
+ if (lastModified <= 0) {
+ lastModified = System.currentTimeMillis();
}
this.createProperty(JcrConstants.JCR_MIMETYPE, mimeType);
- this.createProperty(JcrConstants.JCR_LASTMODIFIED, date);
- // the data property does not need to be added to the enhanced docview as already derived from the binary file
+ this.createProperty(JcrConstants.JCR_LASTMODIFIED, lastModified);
+ this.createProperty(JcrConstants.JCR_DATA, data);
}
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/XMLNodeToXMLFileWriter.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/XMLNodeToXMLFileWriter.java
new file mode 100644
index 0000000..272f300
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/XMLNodeToXMLFileWriter.java
@@ -0,0 +1,111 @@
+/*
+ * 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 javanet.staxutils.IndentingXMLEventWriter;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.feature.cpconverter.handlers.slinginitialcontent.xmlbuffer.XMLNode;
+import org.apache.sling.feature.cpconverter.vltpkg.JcrNamespaceRegistry;
+import org.jetbrains.annotations.NotNull;
+
+import javax.jcr.RepositoryException;
+import javax.xml.stream.XMLEventFactory;
+import javax.xml.stream.XMLEventWriter;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+import static org.apache.jackrabbit.vault.util.JcrConstants.JCR_MIXINTYPES;
+import static org.apache.jackrabbit.vault.util.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.vault.util.JcrConstants.NT_UNSTRUCTURED;
+
+/**
+ * Takes the buffered parent XMLNode and writes it to an actual XML file
+ */
+class XMLNodeToXMLFileWriter {
+
+ private final XMLNode parentNode;
+ private final IndentingXMLEventWriter eventWriter;
+ private final JcrNamespaceRegistry namespaceRegistry;
+ private final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
+
+ XMLNodeToXMLFileWriter(@NotNull XMLNode parentNode,
+ @NotNull OutputStream targetOutputStream,
+ @NotNull JcrNamespaceRegistry namespaceRegistry) throws XMLStreamException {
+ this.parentNode = parentNode;
+ XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(targetOutputStream, StandardCharsets.UTF_8.name());
+ this.eventWriter = new IndentingXMLEventWriter(
+ writer
+ );
+ this.eventWriter.setNewLine("\n");
+ this.namespaceRegistry = namespaceRegistry;
+ this.eventWriter.setNamespaceContext(this.namespaceRegistry);
+
+ }
+
+ void write() throws XMLStreamException, RepositoryException {
+
+ eventWriter.add(eventFactory.createStartDocument());
+ writeNode(parentNode, true);
+ eventWriter.add(eventFactory.createEndDocument());
+
+ }
+
+ void writeNode(@NotNull XMLNode xmlNode, boolean isFirstElement) throws RepositoryException, XMLStreamException {
+
+ eventWriter.add(eventFactory.createStartElement(StringUtils.EMPTY, StringUtils.EMPTY, xmlNode.getXmlElementName()));
+
+ if (isFirstElement) {
+ for (String prefix : namespaceRegistry.getPrefixes()) {
+ eventWriter.add(eventFactory.createNamespace(prefix, namespaceRegistry.getURI(prefix)));
+ }
+ }
+
+ String primaryNodeType = xmlNode.getPrimaryNodeType();
+ String[] mixinNodeTypes = xmlNode.getMixinNodeTypes();
+
+
+ eventWriter.add(eventFactory.createAttribute(JCR_PRIMARYTYPE, StringUtils.isNotBlank(primaryNodeType) ? primaryNodeType : NT_UNSTRUCTURED));
+
+ if (ArrayUtils.isNotEmpty(mixinNodeTypes)) {
+ eventWriter.add(eventFactory.createAttribute(JCR_MIXINTYPES, "[" + String.join(",", mixinNodeTypes) + "]"));
+ }
+
+ for (Map.Entry<String, String> entry : xmlNode.getVltXmlParsedProperties().entrySet()) {
+
+ if (entry.getKey().equals(JCR_PRIMARYTYPE) || entry.getKey().equals(JCR_MIXINTYPES)) {
+ continue;
+ }
+
+ eventWriter.add(eventFactory.createAttribute(entry.getKey(), entry.getValue()));
+ }
+
+ for (XMLNode node : xmlNode.getChildren().values()) {
+ writeNode(node, false);
+ }
+
+ eventWriter.add(eventFactory.createEndElement(StringUtils.EMPTY, StringUtils.EMPTY, xmlNode.getXmlElementName()));
+
+
+ }
+
+
+}
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/xmlbuffer/XMLNode.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/xmlbuffer/XMLNode.java
new file mode 100644
index 0000000..dcad4b6
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/slinginitialcontent/xmlbuffer/XMLNode.java
@@ -0,0 +1,158 @@
+/*
+ * 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.xmlbuffer;
+
+import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Represents an XML node in the buffer to be written in a sling initial content package later
+ */
+public class XMLNode {
+
+ private static final String FORMAT_SINGLE_VALUE = "%s";
+ private static final String FORMAT_SINGLE_VALUE_TYPED = "{%s}%s";
+ private static final String FORMAT_MULTI_VALUE = "[%s]";
+ private static final String FORMAT_MULTI_VALUE_TYPED = "{%s}[%s]";
+
+ private final String basePath;
+ private final String xmlElementName;
+ private final String jcrNodeName;
+ private final String primaryNodeType;
+ private final String[] mixinNodeTypes;
+
+ private final VaultPackageAssembler packageAssembler;
+ private final Map<String, String> vltXmlParsedProperties = new HashMap<>();
+ private final Map<String, XMLNode> children = new LinkedHashMap<>();
+
+ public XMLNode(@NotNull VaultPackageAssembler packageAssembler,
+ @NotNull String basePath,
+ @NotNull String xmlElementName,
+ @Nullable String jcrNodeName,
+ @NotNull String primaryNodeType,
+ @Nullable String[] mixinNodeTypes) {
+ this.packageAssembler = packageAssembler;
+ this.basePath = basePath;
+ this.xmlElementName = xmlElementName;
+ this.jcrNodeName = jcrNodeName;
+ this.primaryNodeType = primaryNodeType;
+ this.mixinNodeTypes = mixinNodeTypes;
+ }
+
+ public void addProperty(@NotNull String name, int propertyType, @NotNull String value) {
+ String propertyTypeName = PropertyType.nameFromValue(propertyType);
+
+ if (propertyType > 0) {
+ vltXmlParsedProperties.put(name, String.format(FORMAT_SINGLE_VALUE_TYPED, propertyTypeName, value));
+ } else {
+ vltXmlParsedProperties.put(name, String.format(FORMAT_SINGLE_VALUE, value));
+ }
+
+ }
+
+ public void addProperty(@NotNull String name, int propertyType, @NotNull String[] values) {
+ String propertyTypeName = PropertyType.nameFromValue(propertyType);
+
+ if (propertyType > 0) {
+ vltXmlParsedProperties.put(name, String.format(FORMAT_MULTI_VALUE_TYPED, propertyTypeName, String.join(",", values)));
+ } else {
+ vltXmlParsedProperties.put(name, String.format(FORMAT_MULTI_VALUE, String.join(",", values)));
+ }
+
+ }
+
+ public void addChildNode(@NotNull String name, @NotNull XMLNode xmlNode) {
+ this.children.put(name, xmlNode);
+ }
+
+ public void addProperty(@NotNull String name, @Nullable Object value) throws RepositoryException {
+ if (value == null) {
+ return;
+ }
+
+ if (value instanceof Long) {
+ vltXmlParsedProperties.put(name, String.format(FORMAT_SINGLE_VALUE_TYPED, "Long", value.toString()));
+ } else if (value instanceof Date) {
+ vltXmlParsedProperties.put(name, String.format(FORMAT_SINGLE_VALUE_TYPED, "Date", ((Date) value).toGMTString()));
+ } else if (value instanceof Calendar) {
+ vltXmlParsedProperties.put(name, String.format(FORMAT_SINGLE_VALUE_TYPED, "Date", ((Calendar) value).getTime().toGMTString()));
+ } else if (value instanceof Double) {
+ vltXmlParsedProperties.put(name, String.format(FORMAT_SINGLE_VALUE_TYPED, "Double", value));
+ } else if (value instanceof Boolean) {
+ boolean theBoolValue = Boolean.parseBoolean(value.toString());
+ vltXmlParsedProperties.put(name, String.format(FORMAT_SINGLE_VALUE_TYPED, "Boolean", theBoolValue));
+ } else if (value instanceof InputStream) {
+ vltXmlParsedProperties.put(name, "{Binary}");
+ String path = "jcr_root/" + this.basePath;
+ try {
+ packageAssembler.addEntry(path, (InputStream) value);
+ } catch (IOException e) {
+ throw new RepositoryException(e);
+ }
+
+ } else {
+ vltXmlParsedProperties.put(name, String.format(FORMAT_SINGLE_VALUE, value));
+ }
+
+ }
+
+ @NotNull
+ public String getPath() {
+ return this.basePath + "/" + this.jcrNodeName;
+ }
+
+ @NotNull
+ public String getXmlElementName() {
+ return xmlElementName;
+ }
+
+ @Nullable
+ public String getJcrNodeName() {
+ return jcrNodeName;
+ }
+
+ @NotNull
+ public String getPrimaryNodeType() {
+ return primaryNodeType;
+ }
+
+ @Nullable
+ public String[] getMixinNodeTypes() {
+ return mixinNodeTypes;
+ }
+
+ @NotNull
+ public Map<String, XMLNode> getChildren() {
+ return children;
+ }
+
+ @NotNull
+ public Map<String, String> getVltXmlParsedProperties() {
+ return vltXmlParsedProperties;
+ }
+}
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/repoinit/createpath/CreatePathSegmentProcessor.java b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/createpath/CreatePathSegmentProcessor.java
index 85a9ea5..70699a1 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/repoinit/createpath/CreatePathSegmentProcessor.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/createpath/CreatePathSegmentProcessor.java
@@ -98,7 +98,7 @@ public class CreatePathSegmentProcessor {
throw new RuntimeException("A fatal error occurred while parsing the '"
+ currentContent
+ "' file, see nested exceptions: "
- + e, e);
+ + e);
}
return false;
}
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandleSlingInitialContentTest.java b/src/test/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandleSlingInitialContentTest.java
index 383d7f8..deaa539 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandleSlingInitialContentTest.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandleSlingInitialContentTest.java
@@ -45,6 +45,8 @@ import java.util.Properties;
import java.util.Set;
import java.util.jar.JarFile;
+import javax.xml.transform.Source;
+
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
@@ -66,6 +68,7 @@ import org.apache.sling.feature.cpconverter.shared.ConverterConstants;
import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
import org.hamcrest.CoreMatchers;
import org.hamcrest.MatcherAssert;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -76,6 +79,10 @@ import org.mockito.junit.MockitoJUnitRunner;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
import org.xml.sax.SAXException;
+import org.xmlunit.builder.Input;
+import org.xmlunit.diff.ComparisonType;
+import org.xmlunit.diff.DOMDifferenceEngine;
+import org.xmlunit.diff.DifferenceEngine;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -241,6 +248,7 @@ public class BundleEntryHandleSlingInitialContentTest extends AbstractBundleEntr
String actualXML = IOUtils.toString(archive.getInputSource(jsonFileDescriptorEntry).getByteStream(), UTF_8);
assertThat(actualXML).and(expectedXML).areSimilar();
+
}
}
@@ -401,6 +409,9 @@ public class BundleEntryHandleSlingInitialContentTest extends AbstractBundleEntr
converter.deployPackages();
+
+
+
// verify generated package
try (VaultPackage vaultPackage = new PackageManagerImpl().open(new File(targetFolder, "mysite.core-apps-1.0.0-SNAPSHOT-cp2fm-converted.zip"));
Archive archive = vaultPackage.getArchive()) {
@@ -471,7 +482,7 @@ public class BundleEntryHandleSlingInitialContentTest extends AbstractBundleEntr
String expectedXML = IOUtils.toString(getClass().getResourceAsStream("bundle-entry-xmls/include-redirectStatus.xml"), UTF_8);
String actualXML = IOUtils.toString(xmlFile, UTF_8);
- assertThat(actualXML).and(expectedXML).areSimilar();
+ assertThat(expectedXML).and(actualXML).areSimilar();
}
}
@@ -651,69 +662,42 @@ public class BundleEntryHandleSlingInitialContentTest extends AbstractBundleEntr
}
}
- @Test
- public void testSlingInitialContentEscapingPropertyValues() throws Exception {
- setUpArchive("/jcr_root/apps/gav/install/aem-aem632-project.core-0.0.1-SNAPSHOT-escaping.jar", "aem-aem632-project.core-0.0.1-SNAPSHOT-escaping.jar");
- DefaultEntryHandlersManager handlersManager = new DefaultEntryHandlersManager();
- converter.setEntryHandlersManager(handlersManager);
-
- File targetFolder = tmpFolder.newFolder();
- when(converter.getArtifactsDeployer()).thenReturn(new SimpleFolderArtifactsDeployer(targetFolder));
- when(converter.isSubContentPackageIncluded("/jcr_root/apps/gav/install/aem-aem632-project.core-0.0.1-SNAPSHOT-escaping.jar-APPLICATION")).thenReturn(true);
-
- VaultPackageAssembler assembler = Mockito.mock(VaultPackageAssembler.class);
- Properties props = new Properties();
- props.setProperty(PackageProperties.NAME_GROUP, "com.aem632");
- props.setProperty(PackageProperties.NAME_NAME, "aem-aem632-project.core");
- props.setProperty(PackageProperties.NAME_VERSION, "0.0.1-SNAPSHOT");
- when(assembler.getPackageProperties()).thenReturn(props);
- converter.setMainPackageAssembler(assembler);
- converter.setAclManager(new DefaultAclManager());
-
- BundleSlingInitialContentExtractor extractor = new BundleSlingInitialContentExtractor();
-
- handler.setBundleSlingInitialContentExtractor(extractor);
- handler.setSlingInitialContentPolicy(SlingInitialContentPolicy.EXTRACT_AND_REMOVE);
- handler.handle("/jcr_root/apps/gav/install/aem-aem632-project.core-0.0.1-SNAPSHOT-escaping.jar", archive, entry, converter);
-
- extractor.addRepoInitExtension(converter.getAssemblers(), featuresManager);
-
- converter.deployPackages();
- // verify generated package
- try (VaultPackage vaultPackage = new PackageManagerImpl().open(new File(targetFolder, "aem-aem632-project.core-apps-0.0.1-SNAPSHOT-cp2fm-converted.zip"));
- Archive archive = vaultPackage.getArchive()) {
- archive.open(true);
- PackageId targetId = PackageId.fromString("com.aem632:aem-aem632-project.core-apps:0.0.1-SNAPSHOT-cp2fm-converted");
- assertEquals(targetId, vaultPackage.getId());
- Entry entry = archive.getEntry("jcr_root/apps/aem632/core/test/.content.xml");
- assertNotNull("Archive does not contain expected item", entry);
-
- String expectedXML = IOUtils.toString(getClass().getResourceAsStream("escaping-test/.content.xml"), UTF_8);
- String actualXML = IOUtils.toString(archive.getInputSource(entry).getByteStream(), UTF_8);
- assertThat(actualXML).and(expectedXML).areSimilar();
- }
- }
-
private void assertResultingEntry(Archive archive, String entryKey) throws IOException, SAXException {
InputStream xmlFile = archive.getInputSource(archive.getEntry("jcr_root/apps/mysite/components/global/" + entryKey +"/.content.xml")).getByteStream();
InputStream expectedXmlFileStream = getClass().getResourceAsStream("bundle-entry-xmls/" + entryKey + ".xml");
String expectedXML = IOUtils.toString(expectedXmlFileStream, UTF_8);
String actualXML = IOUtils.toString(xmlFile, UTF_8);
- assertThat(actualXML).and(expectedXML).areSimilar();
+
+ Source control = Input.fromString(expectedXML).build();
+ Source test = Input.fromString(actualXML).build();
+
+ DifferenceEngine diff = new DOMDifferenceEngine();
+ diff.addDifferenceListener((comparison, outcome) -> {
+
+ if(comparison.getType() == ComparisonType.CHILD_NODELIST_LENGTH){
+ //this comparison is buggy so we can't use it.
+ return;
+ }
+
+ String actualString = comparison.getTestDetails().getValue().toString();
+ String expectedString = comparison.getControlDetails().getValue().toString();
+ if(!actualString.trim().equals(expectedString.trim())){
+ Assert.fail("difference found in XML: " + actualString + " vs " + expectedString);
+ }
+ });
+ diff.compare(control, test);
}
private void assertPageStructureFromEntry(Archive archive, String basePath, String pageName, String... files) throws IOException {
- String entryPath = basePath + "/" + pageName + "/.content.xml";
- Entry contentXml = archive.getEntry(entryPath);
- assertNotNull("could not find entry path " + entryPath + " in archive " + archive, contentXml);
+ Entry contentXml = archive.getEntry( basePath + "/" + pageName + "/.content.xml");
+ assertNotNull(contentXml);
Entry pageXml = archive.getEntry( basePath + "/" + pageName + ".xml");
assertNull(pageXml);
for(String file: files){
- entryPath = basePath + "/" + pageName + "/" + file;
- Entry expectedEntry = archive.getEntry(entryPath);
- assertNotNull("could not find entry path " + entryPath + " in archive " + archive, expectedEntry);
+ Entry expectedEntry = archive.getEntry( basePath + "/" + pageName + "/" + file);
+ assertNotNull(expectedEntry);
}
}
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/aem-aem632-project.core-0.0.1-SNAPSHOT-escaping.jar b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/aem-aem632-project.core-0.0.1-SNAPSHOT-escaping.jar
deleted file mode 100644
index 37e0f13..0000000
Binary files a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/aem-aem632-project.core-0.0.1-SNAPSHOT-escaping.jar and /dev/null differ
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/11mumbojumbo.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/11mumbojumbo.xml
index 1cbee8f..de1f197 100644
--- a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/11mumbojumbo.xml
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/11mumbojumbo.xml
@@ -1,4 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
-<jcr:root xmlns="" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0" jcr:primaryType="cq:Component" prop=" [...]
- <someOtherNode jcr:primaryType="nt:unstructured" prop="property value as string" />
+<jcr:root xmlns="" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0" jcr:primaryType="cq:Component" prop=" [...]
+ <someOtherNode jcr:primaryType="nt:unstructured" prop="{String}property value as string">
+ </someOtherNode>
</jcr:root>
\ No newline at end of file
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/homepage.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/homepage.xml
index ba5b304..7bdf717 100644
--- a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/homepage.xml
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/homepage.xml
@@ -1 +1,3 @@
-<jcr:root xmlns="" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0" jcr:primaryType="cq:Component" sling: [...]
\ No newline at end of file
+<?xml version='1.0' encoding='UTF-8'?>
+<jcr:root xmlns="" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0" jcr:primaryType="cq:Component" sling: [...]
+</jcr:root>
\ No newline at end of file
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/include-redirectStatus.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/include-redirectStatus.xml
index 61e9646..a441d1c 100755
--- a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/include-redirectStatus.xml
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/include-redirectStatus.xml
@@ -1,15 +1,17 @@
<?xml version='1.0' encoding='UTF-8'?>
<jcr:root xmlns="" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0" jcr:primaryType="nt:unstructured" mar [...]
- <items jcr:primaryType="nt:unstructured">
- <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container">
- <items jcr:primaryType="nt:unstructured">
- <redirectStatus jcr:primaryType="nt:unstructured" defaultValue="301" fieldLabel="io.wcm.handler.link.components.global.include.linkRefContainer.redirectStatus.redirectStatus.fieldLabel" name="./redirectStatus" sling:resourceType="granite/ui/components/coral/foundation/form/select" fieldDescription="io.wcm.handler.link.components.global.include.linkRefContainer.redirectStatus.redirectStatus.fieldDescription">
- <items jcr:primaryType="nt:unstructured">
- <_x0033_01 jcr:primaryType="nt:unstructured" text="io.wcm.handler.link.components.global.include.linkRefContainer.redirectStatus.redirectStatus.301" value="301"/>
- <_x0033_02 jcr:primaryType="nt:unstructured" text="io.wcm.handler.link.components.global.include.linkRefContainer.redirectStatus.redirectStatus.302" value="302"/>
- </items>
- </redirectStatus>
- </items>
- </column>
- </items>
+ <items jcr:primaryType="nt:unstructured">
+ <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container">
+ <items jcr:primaryType="nt:unstructured">
+ <redirectStatus jcr:primaryType="nt:unstructured" defaultValue="301" fieldLabel="io.wcm.handler.link.components.global.include.linkRefContainer.redirectStatus.redirectStatus.fieldLabel" name="./redirectStatus" sling:resourceType="granite/ui/components/coral/foundation/form/select" fieldDescription="io.wcm.handler.link.components.global.include.linkRefContainer.redirectStatus.redirectStatus.fieldDescription">
+ <items jcr:primaryType="nt:unstructured">
+ <_301 jcr:primaryType="nt:unstructured" text="io.wcm.handler.link.components.global.include.linkRefContainer.redirectStatus.redirectStatus.301" value="301">
+ </_301>
+ <_302 jcr:primaryType="nt:unstructured" text="io.wcm.handler.link.components.global.include.linkRefContainer.redirectStatus.redirectStatus.302" value="302">
+ </_302>
+ </items>
+ </redirectStatus>
+ </items>
+ </column>
+ </items>
</jcr:root>
\ No newline at end of file
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/nodeName.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/nodeName.xml
index 5de3ccc..c11e395 100644
--- a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/nodeName.xml
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/nodeName.xml
@@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
-<jcr:root xmlns="" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0" jcr:primaryType="nt:unstructured" pro [...]
+<jcr:root xmlns="" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0" jcr:primaryType="nt:unstructured" pro [...]
<testfile.txt jcr:primaryType="nt:file">
- <jcr:content jcr:lastModified="{Date}1977-06-01T06:00:00.000Z" jcr:mimeType="application/test" jcr:primaryType="nt:resource"/>
+ <jcr:content jcr:primaryType="nt:resource" jcr:mimeType="application/test" jcr:data="{Binary}" jcr:lastModified="{Long}233992800000">
+ </jcr:content>
</testfile.txt>
</jcr:root>
\ No newline at end of file
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/xyz.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/xyz.xml
index ac39d93..78dfbe0 100644
--- a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/xyz.xml
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/bundle-entry-xmls/xyz.xml
@@ -1,4 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
-<jcr:root xmlns="" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0" jcr:primaryType="nt:unstructured" jcr [...]
- <someOtherNode jcr:primaryType="nt:unstructured" prop="property value as string"/>
+<jcr:root xmlns="" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0" jcr:primaryType="nt:unstructured" jcr [...]
+ <someOtherNode jcr:primaryType="nt:unstructured" prop="{String}property value as string">
+ </someOtherNode>
</jcr:root>
\ No newline at end of file
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/escaping-test/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/escaping-test/.content.xml
deleted file mode 100644
index d58b5f9..0000000
--- a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/escaping-test/.content.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<jcr:root xmlns="" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0"
- jcr:primaryType="nt:unstructured"
- property1="^/content/wcm-io(-\\w+)?/.+$"
- property2="^/content/wcm-io(-\\\\w+)?/.+$"/>
\ No newline at end of file
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/i18n-jsonfile-xml-descriptor-test/en.json.dir/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/i18n-jsonfile-xml-descriptor-test/en.json.dir/.content.xml
index 08a0c9d..79aadfd 100755
--- a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/i18n-jsonfile-xml-descriptor-test/en.json.dir/.content.xml
+++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/i18n-jsonfile-xml-descriptor-test/en.json.dir/.content.xml
@@ -2,6 +2,7 @@
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:mix="http://www.jcp.org/jcr/mix/1.0"
xmlns:my="http://namespace.com/my"
- jcr:language="en"
+ jcr:language="{String}en"
jcr:mixinTypes="[mix:language]"
- jcr:primaryType="nt:file"/>
\ No newline at end of file
+ jcr:primaryType="nt:file">
+</jcr:root>
\ No newline at end of file