Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -445,4 +445,55 @@ public void testEnhancedFileAggregatePackageWithIntermediateSaves() throws IOExc
assertPropertyExists("/testroot/tika/config.xml/jcr:content/jcr:data");
assertProperty("/testroot/tika/config.xml/jcr:content/jcr:mimeType", "text/xml");
}

@Test
public void testSkipFilterChecksOnImport_disabled() throws Exception {
ImportOptions opts = getDefaultOptions();
Importer importer = new Importer(opts);
try (Archive archive = getFileArchive("/test-packages/outside-filters.zip")) {
archive.open(true);
importer.run(archive, admin.getRootNode());
admin.save();
}
assertNodeExists("/tmp/foo");
assertPropertyMissing("/tmp/foo/bar/tobi/excludeddProp");
Copy link
Member

@kwin kwin Sep 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some assertions what happens to nodes/properties below filter roots not contained in the package.

}

@Test
public void testSkipFilterChecksOnImport_enabled() throws Exception {
ImportOptions opts = getDefaultOptions();
opts.setSkipFilterChecksOnImport(true);
Importer importer = new Importer(opts);
try (Archive archive = getFileArchive("/test-packages/outside-filters.zip")) {
archive.open(true);
importer.run(archive, admin.getRootNode());
admin.save();
}
assertNodeExists("/tmp/foo");
assertPropertyExists("/tmp/foo/bar/tobi/excludedProp");
}

@Test
public void testSkipFilterChecksOnImport_enabled_mergeWithExisting() throws Exception {
ImportOptions opts = getDefaultOptions();
opts.setSkipFilterChecksOnImport(true);
Node tmp= admin.getRootNode().addNode("tmp");
Node tobi = tmp.addNode("foo").addNode("bar").addNode("tobi");
tobi.setProperty("excludedProp", "existingvalue");
tobi.setProperty("excludedProp-foo", "should-survive");
admin.save();
Importer importer = new Importer(opts);
try (Archive archive = getFileArchive("/test-packages/outside-filters.zip")) {
archive.open(true);
importer.run(archive, admin.getRootNode());
admin.save();
}
assertNodeExists("/tmp/foo");
assertPropertyExists("/tmp/foo/bar/tobi/excludedProp");
// import has overwritten existing property
assertProperty("/tmp/foo/bar/tobi/excludedProp", "excluded property");
// but an existing property which is not overwritten by content in the package remains available
assertProperty("/tmp/foo/bar/tobi/excludedProp-foo", "should-survive");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Created-By: 11.0.21 (Eclipse Adoptium)

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<vaultfs version="1.1">
<!--
Defines the content aggregation. The order of the defined aggregates
is important for finding the correct aggregator.
-->
<aggregates>
<!--
Defines an aggregate that handles nt:file and nt:resource nodes.
-->
<aggregate type="file" title="File Aggregate"/>

<!--
Defines an aggregate that handles file/folder like nodes. It matches
all nt:hierarchyNode nodes that have or define a jcr:content
child node and excludes child nodes that are nt:hierarchyNodes.
-->
<aggregate type="filefolder" title="File/Folder Aggregate"/>

<!--
Defines an aggregate that handles nt:nodeType nodes and serializes
them into .cnd notation.
-->
<aggregate type="nodetype" title="Node Type Aggregate" />

<!--
Defines an aggregate that defines full coverage for certain node
types that cannot be covered by the default aggregator.
-->
<aggregate type="full" title="Full Coverage Aggregate">
<matches>
<include nodeType="rep:AccessControl" respectSupertype="true" />
<include nodeType="rep:Policy" respectSupertype="true" />
<include nodeType="cq:Widget" respectSupertype="true" />
<include nodeType="cq:EditConfig" respectSupertype="true" />
<include nodeType="cq:WorkflowModel" respectSupertype="true" />
<include nodeType="vlt:FullCoverage" respectSupertype="true" />
<include nodeType="mix:language" respectSupertype="true" />
<include nodeType="sling:OsgiConfig" respectSupertype="true" />
</matches>
</aggregate>

<!--
Defines an aggregate that handles nt:folder like nodes.
-->
<aggregate type="generic" title="Folder Aggregate">
<matches>
<include nodeType="nt:folder" respectSupertype="true" />
</matches>
<contains>
<exclude isNode="true" />
</contains>
</aggregate>

<!--
Defines the default aggregate
-->
<aggregate type="generic" title="Default Aggregator" isDefault="true">
<matches>
<!-- all -->
</matches>
<contains>
<exclude nodeType="nt:hierarchyNode" respectSupertype="true" />
</contains>
</aggregate>

</aggregates>

<!--
defines the input handlers
-->
<handlers>
<handler type="folder"/>
<handler type="file"/>
<handler type="nodetype"/>
<handler type="generic"/>
</handlers>
</vaultfs>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:vlt="http://www.day.com/jcr/vault/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:created="{Date}2011-06-07T14:31:49.179-07:00"
jcr:createdBy="admin"
jcr:description=""
jcr:lastModified="{Date}2011-06-07T14:31:49.179-07:00"
jcr:lastModifiedBy="admin"
jcr:primaryType="vlt:PackageDefinition"
buildCount="1"
cqVersion="5.3"
group="my_packages"
lastUnwrapped="{Date}2011-06-07T14:31:49.179-07:00"
lastUnwrappedBy="admin"
lastWrapped="{Date}2011-06-07T14:31:49.179-07:00"
lastWrappedBy="admin"
name="tmp"
version="">
<filter jcr:primaryType="nt:unstructured">
<f0
jcr:primaryType="nt:unstructured"
mode="replace"
root="/tmp"
rules="[]"/>
</filter>
</jcr:root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<workspaceFilter version="1.0">
<filter root="/tmp">
<exclude pattern="^.*/excludedProp.*" matchProperties="true"/>
</filter>
</workspaceFilter>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<'sling'='http://sling.apache.org/jcr/sling/1.0'>
<'nt'='http://www.jcp.org/jcr/nt/1.0'>

[sling:Folder] > nt:folder
- * (undefined)
- * (undefined) multiple
+ * (nt:base) = sling:Folder version

[sling:OrderedFolder] > sling:Folder
orderable
+ * (nt:base) = sling:OrderedFolder version

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>FileVault Package Properties</comment>
<entry key="createdBy">admin</entry>
<entry key="name">tmp</entry>
<entry key="lastModified">2011-06-07T14:31:49.179-07:00</entry>
<entry key="lastModifiedBy">admin</entry>
<entry key="created">2011-06-07T14:31:49.418-07:00</entry>
<entry key="buildCount">1</entry>
<entry key="version"/>
<entry key="dependencies"/>
<entry key="packageFormatVersion">2</entry>
<entry key="description"/>
<entry key="group">my_packages</entry>
<entry key="lastWrapped">2011-06-07T14:31:49.179-07:00</entry>
<entry key="lastWrappedBy">admin</entry>
<entry key="path">/etc/packages/my_packages/tmp</entry>
</properties>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
jcr:mixinTypes="[rep:AccessControllable]"
jcr:primaryType="rep:root"
sling:resourceType="sling:redirect"
sling:target="/welcome.html">
<home/>
<rep:policy/>
<jcr:system/>
<etc/>
<apps/>
<libs/>
<content/>
<var/>
<tmp/>
</jcr:root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OrderedFolder">
<foo/>
</jcr:root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OrderedFolder">
<bar/>
</jcr:root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OrderedFolder">
<tobi/>
</jcr:root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OrderedFolder"
excludedProp="excluded property"
/>
Binary file added vault-core/.DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

@Version("2.9.0")
@Version("2.10.0")
package org.apache.jackrabbit.vault.fs.config;

import org.osgi.annotation.versioning.Version;
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,12 @@ public void dump(DumpContext ctx, boolean isLast) {
ctx.println(isLast, getClass().getSimpleName());
}

protected ImportInfoImpl importDocView(InputSource source, Node parentNode, String rootNodeName, ArtifactSetImpl artifacts, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy) throws IOException, RepositoryException {
return importDocView(source, parentNode, rootNodeName, artifacts, true, wspFilter, idConflictPolicy);
protected ImportInfoImpl importDocView(InputSource source, Node parentNode, String rootNodeName, ArtifactSetImpl artifacts, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy, boolean skipFilterChecksOnImport) throws IOException, RepositoryException {
return importDocView(source, parentNode, rootNodeName, artifacts, true, wspFilter, idConflictPolicy, skipFilterChecksOnImport);
}

protected ImportInfoImpl importDocView(InputSource source, Node parentNode, String rootNodeName, ArtifactSetImpl artifacts, boolean isStrict, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy) throws IOException, RepositoryException {
DocViewImporter handler = new DocViewImporter(parentNode, rootNodeName, artifacts, wspFilter, idConflictPolicy, getAcHandling(), getCugHandling());
protected ImportInfoImpl importDocView(InputSource source, Node parentNode, String rootNodeName, ArtifactSetImpl artifacts, boolean isStrict, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy, boolean skipFilterChecksOnImport) throws IOException, RepositoryException {
DocViewImporter handler = new DocViewImporter(parentNode, rootNodeName, artifacts, wspFilter, idConflictPolicy, getAcHandling(), getCugHandling(), skipFilterChecksOnImport);
String rootNodePath = parentNode.getPath();
if (!rootNodePath.equals("/")) {
rootNodePath += "/";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import org.apache.jackrabbit.vault.fs.api.IdConflictPolicy;
import org.apache.jackrabbit.vault.fs.api.ImportInfo.Info;
import org.apache.jackrabbit.vault.fs.api.ImportInfo.Type;
import org.apache.jackrabbit.vault.fs.config.DefaultWorkspaceFilter;
import org.apache.jackrabbit.vault.fs.api.ImportMode;
import org.apache.jackrabbit.vault.fs.api.ItemFilterSet;
import org.apache.jackrabbit.vault.fs.api.NodeNameList;
Expand Down Expand Up @@ -225,6 +226,11 @@ public class DocViewImporter implements DocViewParserHandler {
*/
private final boolean isSnsSupported;

/**
* set true if filter checks can be skipped on import
*/
private boolean skipFilterChecksOnImport = false;

/**
* Creates a new importer that will imports the
* items below the given root.
Expand All @@ -236,12 +242,12 @@ public class DocViewImporter implements DocViewParserHandler {
* @throws RepositoryException if an error occurs.
*/
public DocViewImporter(Node parentNode, String rootNodeName,
ArtifactSetImpl artifacts, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy) throws RepositoryException {
this(parentNode, rootNodeName, artifacts, wspFilter, idConflictPolicy, AccessControlHandling.IGNORE, null);
ArtifactSetImpl artifacts, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy, boolean skipFilterChecksOnImport) throws RepositoryException {
this(parentNode, rootNodeName, artifacts, wspFilter, idConflictPolicy, AccessControlHandling.IGNORE, null, skipFilterChecksOnImport);
}

public DocViewImporter(Node parentNode, String rootNodeName,
ArtifactSetImpl artifacts, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy, AccessControlHandling aclHandling, AccessControlHandling cugHandling) throws RepositoryException {
ArtifactSetImpl artifacts, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy, AccessControlHandling aclHandling, AccessControlHandling cugHandling, boolean skipFilterChecksOnImport) throws RepositoryException {
this.filter = artifacts.getCoverage();
this.wspFilter = wspFilter;
this.rootDepth = parentNode.getDepth() + 1;
Expand Down Expand Up @@ -270,9 +276,11 @@ public DocViewImporter(Node parentNode, String rootNodeName,
for (Artifact a : artifacts.values(ArtifactType.HINT)) {
hints.add(rootPath + a.getRelativePath());
}

stack = new StackElement(parentNode, parentNode.isNew());
npResolver = new DefaultNamePathResolver(parentNode.getSession());

this.skipFilterChecksOnImport = skipFilterChecksOnImport;
}

/**
Expand Down Expand Up @@ -1014,7 +1022,8 @@ private void removeReferences(@NotNull Node node) throws ReferentialIntegrityExc
// TODO: is this faster than using sysview import?
// set new primary type (but never set rep:root)
String newPrimaryType = ni.getPrimaryType().orElseThrow(() -> new IllegalStateException("Mandatory property 'jcr:primaryType' missing from " + ni));
if (importMode == ImportMode.REPLACE && !"rep:root".equals(newPrimaryType) && wspFilter.includesProperty(PathUtil.append(node.getPath(), JcrConstants.JCR_PRIMARYTYPE))) {
final boolean allowedByFilter = (skipFilterChecksOnImport || wspFilter.includesProperty(PathUtil.append(node.getPath(), JcrConstants.JCR_PRIMARYTYPE)));
if (importMode == ImportMode.REPLACE && !"rep:root".equals(newPrimaryType) && allowedByFilter) {
String currentPrimaryType = node.getPrimaryNodeType().getName();
if (!currentPrimaryType.equals(newPrimaryType)) {
vs.ensureCheckedOut();
Expand Down Expand Up @@ -1157,7 +1166,8 @@ private void removeReferences(@NotNull Node node) throws ReferentialIntegrityExc
// add the protected properties
for (DocViewProperty2 p : ni.getProperties()) {
String qualifiedPropertyName = npResolver.getJCRName(p.getName());
if (p.getStringValue().isPresent() && PROTECTED_PROPERTIES_CONSIDERED_FOR_NEW_NODES.contains(p.getName()) && wspFilter.includesProperty(nodePath + "/" + qualifiedPropertyName)) {
final boolean allowedByFilter = (skipFilterChecksOnImport || wspFilter.includesProperty(nodePath + "/" + qualifiedPropertyName));
if (p.getStringValue().isPresent() && PROTECTED_PROPERTIES_CONSIDERED_FOR_NEW_NODES.contains(p.getName()) && allowedByFilter) {
attrs = new AttributesImpl();
attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", ATTRIBUTE_TYPE_CDATA, qualifiedPropertyName);
attrs.addAttribute(Name.NS_SV_URI, "type", "sv:type", ATTRIBUTE_TYPE_CDATA, PropertyType.nameFromValue(p.getType()));
Expand Down Expand Up @@ -1277,7 +1287,8 @@ private boolean setUnprotectedProperties(@NotNull EffectiveNodeType effectiveNod
// add properties
for (DocViewProperty2 prop : ni.getProperties()) {
String name = npResolver.getJCRName(prop.getName());
if (prop != null && !isPropertyProtected(effectiveNodeType, prop) && (overwriteExistingProperties || !node.hasProperty(name)) && wspFilter.includesProperty(node.getPath() + "/" + name)) {
final boolean allowedByFilter = (skipFilterChecksOnImport || wspFilter.includesProperty(node.getPath() + "/" + name));
if (prop != null && !isPropertyProtected(effectiveNodeType, prop) && (overwriteExistingProperties || !node.hasProperty(name)) && allowedByFilter) {
// check if property is allowed
try {
modified |= prop.apply(node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ public ImportInfoImpl accept(@NotNull ImportOptions options, boolean isStrictByD
mode = wspFilter.getImportMode(path);
}
if (mode != ImportMode.MERGE) {
info.merge(importDocView(file.getInputSource(), newParent, newName, newSet, wspFilter, options.getIdConflictPolicy()));
info.merge(importDocView(file.getInputSource(), newParent, newName, newSet, wspFilter, options.getIdConflictPolicy(), options.getSkipFilterChecksOnImport()));
} else {
info.onNop(path);
}
Expand Down Expand Up @@ -315,7 +315,7 @@ private ImportInfoImpl importDocView(Node parent, InputSource source,
if (idx > 0) {
rootName = rootName.substring(0, idx);
}
return importDocView(source, parent, rootName, artifacts, wspFilter, options.getIdConflictPolicy());
return importDocView(source, parent, rootName, artifacts, wspFilter, options.getIdConflictPolicy(),options.getSkipFilterChecksOnImport());
}

private boolean importNtResource(ImportInfo info, Node content, Artifact artifact)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public ImportInfoImpl accept(@NotNull ImportOptions options, boolean isStrictByD
}
}
}
info.merge(importDocView(source, parent, name, artifacts, options.isStrict(isStrictByDefault), wspFilter, options.getIdConflictPolicy()));
info.merge(importDocView(source, parent, name, artifacts, options.isStrict(isStrictByDefault), wspFilter, options.getIdConflictPolicy(), options.getSkipFilterChecksOnImport()));
}
return info;
}
Expand Down
Loading