You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2021/03/16 15:37:46 UTC
[jackrabbit-filevault] branch master updated: JCRVLT-511 add
package task options (#128)
This is an automated email from the ASF dual-hosted git repository.
kwin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git
The following commit(s) were added to refs/heads/master by this push:
new d3c81ba JCRVLT-511 add package task options (#128)
d3c81ba is described below
commit d3c81ba1b3fb36eb52824b8d4ab1c9506eb5bbbb
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Tue Mar 16 16:37:37 2021 +0100
JCRVLT-511 add package task options (#128)
---
.../jackrabbit/vault/fs/io/ImportOptions.java | 105 +++++++++++++++
.../jackrabbit/vault/fs/io/package-info.java | 2 +-
.../vault/packaging/registry/PackageTask.java | 7 +
.../packaging/registry/PackageTaskBuilder.java | 10 +-
.../{package-info.java => PackageTaskOptions.java} | 5 +-
.../registry/impl/ExecutionPlanBuilderImpl.java | 53 +++++---
.../packaging/registry/impl/PackageTaskImpl.java | 73 ++++++++--
.../impl/PackageTaskOptionsSerializer.java | 149 +++++++++++++++++++++
.../vault/packaging/registry/package-info.java | 2 +-
.../taskoption/ImportOptionsPackageTaskOption.java | 66 +++++++++
.../impl/ExecutionPlanBuilderImplTest.java | 78 +++++++++++
.../registry/impl/MockPackageRegistry.java | 5 +-
12 files changed, 526 insertions(+), 29 deletions(-)
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ImportOptions.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ImportOptions.java
index bff88c1..5ab14ee 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ImportOptions.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/ImportOptions.java
@@ -405,4 +405,109 @@ public class ImportOptions {
public void setDependencyHandling(DependencyHandling dependencyHandling) {
this.dependencyHandling = dependencyHandling;
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((acHandling == null) ? 0 : acHandling.hashCode());
+ result = prime * result + autoSave;
+ result = prime * result + ((cndPattern == null) ? 0 : cndPattern.hashCode());
+ result = prime * result + ((cugHandling == null) ? 0 : cugHandling.hashCode());
+ result = prime * result + ((dependencyHandling == null) ? 0 : dependencyHandling.hashCode());
+ result = prime * result + (dryRun ? 1231 : 1237);
+ result = prime * result + ((filter == null) ? 0 : filter.hashCode());
+ result = prime * result + ((hookClassLoader == null) ? 0 : hookClassLoader.hashCode());
+ result = prime * result + ((importMode == null) ? 0 : importMode.hashCode());
+ result = prime * result + ((listener == null) ? 0 : listener.hashCode());
+ result = prime * result + (nonRecursive ? 1231 : 1237);
+ result = prime * result + ((patchDirectory == null) ? 0 : patchDirectory.hashCode());
+ result = prime * result + (patchKeepInRepo ? 1231 : 1237);
+ result = prime * result + ((patchParentPath == null) ? 0 : patchParentPath.hashCode());
+ result = prime * result + ((pathMapping == null) ? 0 : pathMapping.hashCode());
+ result = prime * result + (strict ? 1231 : 1237);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ImportOptions other = (ImportOptions) obj;
+ if (acHandling != other.acHandling)
+ return false;
+ if (autoSave != other.autoSave)
+ return false;
+ if (cndPattern == null) {
+ if (other.cndPattern != null)
+ return false;
+ } else if (!cndPattern.pattern().equals(other.cndPattern.pattern()))
+ return false;
+ if (cugHandling != other.cugHandling)
+ return false;
+ if (dependencyHandling != other.dependencyHandling)
+ return false;
+ if (dryRun != other.dryRun)
+ return false;
+ if (filter == null) {
+ if (other.filter != null)
+ return false;
+ } else if (!filter.equals(other.filter))
+ return false;
+ if (hookClassLoader == null) {
+ if (other.hookClassLoader != null)
+ return false;
+ } else if (!hookClassLoader.equals(other.hookClassLoader))
+ return false;
+ if (importMode != other.importMode)
+ return false;
+ if (listener == null) {
+ if (other.listener != null)
+ return false;
+ } else if (!listener.equals(other.listener))
+ return false;
+ if (nonRecursive != other.nonRecursive)
+ return false;
+ if (patchDirectory == null) {
+ if (other.patchDirectory != null)
+ return false;
+ } else if (!patchDirectory.equals(other.patchDirectory))
+ return false;
+ if (patchKeepInRepo != other.patchKeepInRepo)
+ return false;
+ if (patchParentPath == null) {
+ if (other.patchParentPath != null)
+ return false;
+ } else if (!patchParentPath.equals(other.patchParentPath))
+ return false;
+ if (pathMapping == null) {
+ if (other.pathMapping != null)
+ return false;
+ } else if (!pathMapping.equals(other.pathMapping))
+ return false;
+ if (strict != other.strict)
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "ImportOptions [strict=" + strict + ", " + (listener != null ? "listener=" + listener + ", " : "")
+ + (patchParentPath != null ? "patchParentPath=" + patchParentPath + ", " : "")
+ + (patchDirectory != null ? "patchDirectory=" + patchDirectory + ", " : "") + "patchKeepInRepo=" + patchKeepInRepo
+ + ", nonRecursive=" + nonRecursive + ", dryRun=" + dryRun + ", autoSave=" + autoSave + ", "
+ + (acHandling != null ? "acHandling=" + acHandling + ", " : "")
+ + (cugHandling != null ? "cugHandling=" + cugHandling + ", " : "")
+ + (importMode != null ? "importMode=" + importMode + ", " : "")
+ + (cndPattern != null ? "cndPattern=" + cndPattern + ", " : "") + (filter != null ? "filter=" + filter + ", " : "")
+ + (hookClassLoader != null ? "hookClassLoader=" + hookClassLoader + ", " : "")
+ + (pathMapping != null ? "pathMapping=" + pathMapping + ", " : "")
+ + (dependencyHandling != null ? "dependencyHandling=" + dependencyHandling : "") + "]";
+ }
+
+
}
\ No newline at end of file
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/package-info.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/package-info.java
index 2145118..ac05198 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/package-info.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/package-info.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-@Version("2.9.1")
+@Version("2.9.2")
package org.apache.jackrabbit.vault.fs.io;
import org.osgi.annotation.versioning.Version;
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/PackageTask.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/PackageTask.java
index 15c0b31..42396c4 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/PackageTask.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/PackageTask.java
@@ -90,6 +90,13 @@ public interface PackageTask {
Type getType();
/**
+ * Returns the task optional options.
+ * @return the task options (may be null).
+ */
+ @Nullable
+ PackageTaskOptions getOptions();
+
+ /**
* Returns the task state
* @return the task state
*/
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/PackageTaskBuilder.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/PackageTaskBuilder.java
index 29d1666..925b951 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/PackageTaskBuilder.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/PackageTaskBuilder.java
@@ -37,9 +37,17 @@ public interface PackageTaskBuilder {
/**
* Sets the type of this task
* @param type the type
- * @return this.
+ * @return the parent execution plan builder.
*/
@NotNull
ExecutionPlanBuilder with(@NotNull PackageTask.Type type);
+
+ /**
+ * Set the optional options for the package task
+ * @param options the options
+ * @return this.
+ */
+ @NotNull
+ PackageTaskBuilder withOptions(@NotNull PackageTaskOptions options);
}
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/package-info.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/PackageTaskOptions.java
similarity index 94%
copy from vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/package-info.java
copy to vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/PackageTaskOptions.java
index c96debb..0098d76 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/package-info.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/PackageTaskOptions.java
@@ -14,5 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@org.osgi.annotation.versioning.Version("1.3.1")
package org.apache.jackrabbit.vault.packaging.registry;
+
+public interface PackageTaskOptions {
+
+}
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/ExecutionPlanBuilderImpl.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/ExecutionPlanBuilderImpl.java
index 5fdca4e..8888aea 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/ExecutionPlanBuilderImpl.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/ExecutionPlanBuilderImpl.java
@@ -48,11 +48,13 @@ import org.apache.jackrabbit.vault.packaging.registry.ExecutionPlanBuilder;
import org.apache.jackrabbit.vault.packaging.registry.PackageRegistry;
import org.apache.jackrabbit.vault.packaging.registry.PackageTask;
import org.apache.jackrabbit.vault.packaging.registry.PackageTaskBuilder;
+import org.apache.jackrabbit.vault.packaging.registry.PackageTaskOptions;
import org.apache.jackrabbit.vault.packaging.registry.RegisteredPackage;
import org.apache.jackrabbit.vault.util.RejectingEntityResolver;
import org.apache.jackrabbit.vault.util.xml.serialize.FormattingXmlStreamWriter;
import org.apache.jackrabbit.vault.util.xml.serialize.OutputFormat;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
@@ -71,7 +73,7 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
*/
private static final Logger log = LoggerFactory.getLogger(ExecutionPlanBuilderImpl.class);
- private final static String ATTR_VERSION = "version";
+ private static final String ATTR_VERSION = "version";
private static final String TAG_EXECUTION_PLAN = "executionPlan";
private static final String TAG_TASK = "task";
private static final String ATTR_CMD = "cmd";
@@ -81,10 +83,12 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
protected double version = SUPPORTED_VERSION;
- private final List<TaskBuilder> tasks = new LinkedList<TaskBuilder>();
+ private final List<TaskBuilder> tasks = new LinkedList<>();
private final PackageRegistry registry;
+ private final PackageTaskOptionsSerializer optionsSerializer;
+
private Session session;
private ProgressTrackerListener listener;
@@ -95,6 +99,7 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
ExecutionPlanBuilderImpl(PackageRegistry registry) {
this.registry = registry;
+ optionsSerializer = new PackageTaskOptionsSerializer();
}
@NotNull
@@ -109,6 +114,7 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
writer.writeStartElement(TAG_TASK);
writer.writeAttribute(ATTR_CMD, task.getType().name().toLowerCase());
writer.writeAttribute(ATTR_PACKAGE_ID, task.getPackageId().toString());
+ optionsSerializer.save(writer, task.getOptions());
writer.writeEndElement();
}
writer.writeEndElement();
@@ -168,7 +174,13 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
private void readTask(Element elem) throws IOException {
PackageTask.Type type = PackageTask.Type.valueOf(elem.getAttribute(ATTR_CMD).toUpperCase());
PackageId id = PackageId.fromString(elem.getAttribute(ATTR_PACKAGE_ID));
- addTask().with(id).with(type);
+
+ PackageTaskBuilder packageTaskBuilder = addTask().with(id);
+ PackageTaskOptions options = optionsSerializer.load(elem);
+ if (options != null) {
+ packageTaskBuilder.withOptions(options);
+ }
+ packageTaskBuilder.with(type);
}
@NotNull
@@ -197,10 +209,10 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
@NotNull
@Override
public ExecutionPlanBuilder validate() throws IOException, PackageException {
- Map<PackageId, PackageTask> installTasks = new HashMap<PackageId, PackageTask>();
- Map<PackageId, PackageTask> uninstallTasks = new HashMap<PackageId, PackageTask>();
- Map<PackageId, PackageTask> removeTasks = new HashMap<PackageId, PackageTask>();
- List<PackageTask> packageTasks = new ArrayList<PackageTask>(tasks.size());
+ Map<PackageId, PackageTask> installTasks = new HashMap<>();
+ Map<PackageId, PackageTask> uninstallTasks = new HashMap<>();
+ Map<PackageId, PackageTask> removeTasks = new HashMap<>();
+ List<PackageTask> packageTasks = new ArrayList<>(tasks.size());
for (TaskBuilder task: tasks) {
if (task.id == null || task.type == null) {
throw new PackageException("task builder must have package id and type defined.");
@@ -208,7 +220,7 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
if (!registry.contains(task.id)) {
throw new NoSuchPackageException("No such package: " + task.id);
}
- PackageTaskImpl pTask = new PackageTaskImpl(task.id, task.type);
+ PackageTaskImpl pTask = new PackageTaskImpl(task.id, task.type, task.option);
// very simple task resolution: uninstall -> remove -> install/extract
switch (task.type) {
case INSTALL:
@@ -225,14 +237,15 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
}
for (PackageId id: uninstallTasks.keySet().toArray(new PackageId[uninstallTasks.size()])) {
- resolveUninstall(id, packageTasks, uninstallTasks, new HashSet<PackageId>());
+ resolveUninstall(id, packageTasks, uninstallTasks, new HashSet<>(), uninstallTasks.get(id).getOptions());
}
// todo: validate remove
packageTasks.addAll(removeTasks.values());
for (PackageId id: installTasks.keySet().toArray(new PackageId[installTasks.size()])) {
- resolveInstall(id, packageTasks, installTasks, new HashSet<PackageId>(), installTasks.get(id).getType());
+ PackageTask task = installTasks.get(id);
+ resolveInstall(id, packageTasks, installTasks, new HashSet<>(), task.getType(), task.getOptions());
}
for (PackageTask task: packageTasks) {
@@ -243,7 +256,7 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
return this;
}
- private void resolveInstall(PackageId id, List<PackageTask> packageTasks, Map<PackageId, PackageTask> installTasks, Set<PackageId> resolved, PackageTask.Type type) throws IOException, PackageException {
+ private void resolveInstall(PackageId id, List<PackageTask> packageTasks, Map<PackageId, PackageTask> installTasks, Set<PackageId> resolved, PackageTask.Type type, @Nullable PackageTaskOptions option) throws IOException, PackageException {
if (resolved.contains(id)) {
throw new CyclicDependencyException("Package has cyclic dependencies: " + id);
}
@@ -263,7 +276,7 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
continue;
}
}
- resolveInstall(depId, packageTasks, installTasks, resolved, type);
+ resolveInstall(depId, packageTasks, installTasks, resolved, type, option);
}
PackageTask task = installTasks.get(id);
if (task == PackageTaskImpl.MARKER) {
@@ -274,7 +287,7 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
if (task == null) {
// package is not registered in plan, but need to be installed
// due to dependency
- task = new PackageTaskImpl(id, type);
+ task = new PackageTaskImpl(id, type, option);
}
packageTasks.add(task);
}
@@ -282,7 +295,7 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
installTasks.put(id, PackageTaskImpl.MARKER);
}
- private void resolveUninstall(PackageId id, List<PackageTask> packageTasks, Map<PackageId, PackageTask> uninstallTasks, Set<PackageId> resolved) throws IOException, PackageException {
+ private void resolveUninstall(PackageId id, List<PackageTask> packageTasks, Map<PackageId, PackageTask> uninstallTasks, Set<PackageId> resolved, @Nullable PackageTaskOptions option) throws IOException, PackageException {
if (resolved.contains(id)) {
throw new CyclicDependencyException("Package has cyclic dependencies: " + id);
}
@@ -298,7 +311,7 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
continue;
}
}
- resolveUninstall(depId, packageTasks, uninstallTasks, resolved);
+ resolveUninstall(depId, packageTasks, uninstallTasks, resolved, option);
}
PackageTask task = uninstallTasks.get(id);
if (task == PackageTaskImpl.MARKER) {
@@ -307,7 +320,7 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
}
if (task == null) {
// package is not registered in plan, but need to be installed due to dependency
- task = new PackageTaskImpl(id, PackageTask.Type.UNINSTALL);
+ task = new PackageTaskImpl(id, PackageTask.Type.UNINSTALL, option);
}
packageTasks.add(task);
// mark as processed
@@ -334,6 +347,7 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
private class TaskBuilder implements PackageTaskBuilder {
private PackageId id;
private PackageTask.Type type;
+ private PackageTaskOptions option;
public PackageTaskBuilder with(@NotNull PackageId id) {
this.id = id;
@@ -346,6 +360,13 @@ public class ExecutionPlanBuilderImpl implements ExecutionPlanBuilder {
this.type = type;
return ExecutionPlanBuilderImpl.this;
}
+
+ @Override
+ @NotNull
+ public PackageTaskBuilder withOptions(@NotNull PackageTaskOptions option) {
+ this.option = option;
+ return this;
+ }
}
@Override
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/PackageTaskImpl.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/PackageTaskImpl.java
index ed1fdae..391910c 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/PackageTaskImpl.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/PackageTaskImpl.java
@@ -25,7 +25,9 @@ import org.apache.jackrabbit.vault.packaging.PackageException;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.apache.jackrabbit.vault.packaging.registry.PackageRegistry;
import org.apache.jackrabbit.vault.packaging.registry.PackageTask;
+import org.apache.jackrabbit.vault.packaging.registry.PackageTaskOptions;
import org.apache.jackrabbit.vault.packaging.registry.RegisteredPackage;
+import org.apache.jackrabbit.vault.packaging.registry.taskoption.ImportOptionsPackageTaskOption;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
@@ -41,19 +43,22 @@ public class PackageTaskImpl implements PackageTask {
*/
private static final Logger log = LoggerFactory.getLogger(PackageTaskImpl.class);
- final static PackageTaskImpl MARKER = new PackageTaskImpl(new PackageId("", "" ,""), Type.INSTALL);
+ final static PackageTaskImpl MARKER = new PackageTaskImpl(new PackageId("", "" ,""), Type.INSTALL, null);
private final PackageId id;
private final Type type;
- private State state = State.NEW;
+ private final PackageTaskOptions options;
+
+ State state = State.NEW;
private Throwable error;
- PackageTaskImpl(@NotNull PackageId id, @NotNull Type type) {
+ PackageTaskImpl(@NotNull PackageId id, @NotNull Type type, @Nullable PackageTaskOptions options) {
this.id = id;
this.type = type;
+ this.options = options;
}
@NotNull
@@ -68,6 +73,12 @@ public class PackageTaskImpl implements PackageTask {
return type;
}
+ @Nullable
+ @Override
+ public PackageTaskOptions getOptions() {
+ return options;
+ }
+
@NotNull
@Override
public State getState() {
@@ -82,10 +93,9 @@ public class PackageTaskImpl implements PackageTask {
@Override
public String toString() {
- return "PackageTaskImpl{" + "id=" + id +
- ", type=" + type +
- ", state=" + state +
- '}';
+ return "PackageTaskImpl [" + (id != null ? "id=" + id + ", " : "") + (type != null ? "type=" + type + ", " : "")
+ + (options != null ? "option=" + options + ", " : "") + (state != null ? "state=" + state + ", " : "")
+ + (error != null ? "error=" + error : "") + "]";
}
void execute(ExecutionPlanImpl executionPlan) {
@@ -164,7 +174,12 @@ public class PackageTaskImpl implements PackageTask {
* @throws PackageException if a package error occurs
*/
private void doInstall(ExecutionPlanImpl plan, boolean extract) throws IOException, PackageException {
- ImportOptions opts = new ImportOptions();
+ final ImportOptions opts;
+ if (options instanceof ImportOptionsPackageTaskOption) {
+ opts = ((ImportOptionsPackageTaskOption) options).getImportOptions().copy();
+ } else {
+ opts = new ImportOptions();
+ }
opts.setListener(plan.getListener());
// execution plan resolution already has resolved all dependencies, so there is no need to use best effort here.
opts.setDependencyHandling(DependencyHandling.STRICT);
@@ -180,5 +195,47 @@ public class PackageTaskImpl implements PackageTask {
}
}
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((error == null) ? 0 : error.hashCode());
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + ((options == null) ? 0 : options.hashCode());
+ result = prime * result + ((state == null) ? 0 : state.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ PackageTaskImpl other = (PackageTaskImpl) obj;
+ if (error == null) {
+ if (other.error != null)
+ return false;
+ } else if (!error.equals(other.error))
+ return false;
+ if (id == null) {
+ if (other.id != null)
+ return false;
+ } else if (!id.equals(other.id))
+ return false;
+ if (options == null) {
+ if (other.options != null)
+ return false;
+ } else if (!options.equals(other.options))
+ return false;
+ if (state != other.state)
+ return false;
+ if (type != other.type)
+ return false;
+ return true;
+ }
}
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/PackageTaskOptionsSerializer.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/PackageTaskOptionsSerializer.java
new file mode 100644
index 0000000..e6bbe80
--- /dev/null
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/impl/PackageTaskOptionsSerializer.java
@@ -0,0 +1,149 @@
+/*
+ * 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.jackrabbit.vault.packaging.registry.impl;
+
+import java.util.function.Consumer;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.jackrabbit.vault.fs.api.ImportMode;
+import org.apache.jackrabbit.vault.fs.io.AccessControlHandling;
+import org.apache.jackrabbit.vault.fs.io.ImportOptions;
+import org.apache.jackrabbit.vault.packaging.DependencyHandling;
+import org.apache.jackrabbit.vault.packaging.registry.PackageTaskOptions;
+import org.apache.jackrabbit.vault.packaging.registry.taskoption.ImportOptionsPackageTaskOption;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class PackageTaskOptionsSerializer {
+
+ private static final String TAG_OPTIONS = "options";
+ private static final String ATTR_TYPE = "type";
+ private static final String TAG_AC_HANDLING = "acHandling";
+ private static final String TAG_IS_STRICT = "isStrict";
+ private static final String TAG_AUTO_SAVE_THRESHOLD = "autoSaveThreshold";
+ private static final String TAG_DEPENDENCY_HANDLING = "dependencyHandling";
+ private static final String TAG_CUG_HANDLING = "cugHandling";
+ private static final String TAG_NON_RECURSIVE = "nonRecursive";
+ private static final String TAG_DRY_RUN = "dryRun";
+ private static final String TAG_IMPORT_MODE = "importMode";
+
+ enum Type {
+ ImportOptions;
+
+ static Type fromClass(PackageTaskOptions options) {
+ if (options instanceof ImportOptionsPackageTaskOption) {
+ return ImportOptions;
+ } else {
+ throw new IllegalStateException("Unsupported task option class " + options.getClass());
+ }
+ }
+ }
+
+ public PackageTaskOptions load(Element element) {
+ Element childElement = getFirstElementByTagName(TAG_OPTIONS, element);
+ if (childElement == null) {
+ return null;
+ }
+ final PackageTaskOptions options;
+ switch (Type.valueOf(childElement.getAttribute(ATTR_TYPE))) {
+ case ImportOptions:
+ options = loadImportOptions(childElement);
+ break;
+ default:
+ throw new IllegalArgumentException("Wrong type used");
+ }
+ return options;
+ }
+
+ public void save(XMLStreamWriter writer, PackageTaskOptions options) throws XMLStreamException {
+ if (options == null) {
+ return;
+ }
+ writer.writeStartElement(TAG_OPTIONS);
+ Type type = Type.fromClass(options);
+ writer.writeAttribute(ATTR_TYPE, type.name());
+ switch (type) {
+ case ImportOptions:
+ saveImportOptions(writer, (ImportOptionsPackageTaskOption) options);
+ break;
+ }
+ writer.writeEndElement();
+ }
+
+ public void saveImportOptions(XMLStreamWriter writer, ImportOptionsPackageTaskOption options) throws XMLStreamException {
+ ImportOptions importOptions = options.getImportOptions();
+ writeOption(writer, TAG_IS_STRICT, Boolean.class, importOptions.isStrict());
+ writeOption(writer, TAG_AC_HANDLING, AccessControlHandling.class, importOptions.getAccessControlHandling());
+ writeOption(writer, TAG_CUG_HANDLING, AccessControlHandling.class, importOptions.getCugHandling());
+ writeOption(writer, TAG_AUTO_SAVE_THRESHOLD, Integer.class, importOptions.getAutoSaveThreshold());
+ writeOption(writer, TAG_DEPENDENCY_HANDLING, DependencyHandling.class, importOptions.getDependencyHandling());
+ writeOption(writer, TAG_NON_RECURSIVE, Boolean.class, importOptions.isNonRecursive());
+ writeOption(writer, TAG_DRY_RUN, Boolean.class, importOptions.isDryRun());
+ writeOption(writer, TAG_IMPORT_MODE, ImportMode.class, importOptions.getImportMode());
+ }
+
+ public ImportOptionsPackageTaskOption loadImportOptions(Element element) {
+ ImportOptions options = new ImportOptions();
+ readOption(element, TAG_IS_STRICT, Boolean.class, options::setStrict);
+ readOption(element, TAG_AC_HANDLING, AccessControlHandling.class, options::setAccessControlHandling);
+ readOption(element, TAG_CUG_HANDLING, AccessControlHandling.class, options::setCugHandling);
+ readOption(element, TAG_AUTO_SAVE_THRESHOLD, Integer.class, options::setAutoSaveThreshold);
+ readOption(element, TAG_DEPENDENCY_HANDLING, DependencyHandling.class, options::setDependencyHandling);
+ readOption(element, TAG_NON_RECURSIVE, Boolean.class, options::setNonRecursive);
+ readOption(element, TAG_DRY_RUN, Boolean.class, options::setDryRun);
+ readOption(element, TAG_IMPORT_MODE, ImportMode.class, options::setImportMode);
+ return new ImportOptionsPackageTaskOption(options);
+ }
+
+ private <T> void writeOption(XMLStreamWriter writer, String tagElement, Class<T> type, T value) throws XMLStreamException {
+ if (value != null) {
+ writer.writeStartElement(tagElement);
+ if (type.equals(Boolean.class)) {
+ writer.writeCharacters(Boolean.toString((Boolean)value));
+ } else if (type.isEnum()) {
+ writer.writeCharacters(((Enum<?>)value).name());
+ } else if (type.equals(Integer.class)) {
+ writer.writeCharacters(Integer.toString((Integer)value));
+ }
+ writer.writeEndElement();
+ }
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private <T> void readOption(Element element, String tagName, Class<T> type, Consumer<T> consumer) {
+ Element childElement = getFirstElementByTagName(tagName, element);
+ if (childElement != null) {
+ if (type.equals(Boolean.class)) {
+ consumer.accept((T)Boolean.valueOf(childElement.getTextContent()));
+ } else if (type.isEnum()) {
+ consumer.accept((T)Enum.valueOf((Class)type, childElement.getTextContent()));
+ } else if (type.equals(Integer.class)) {
+ consumer.accept((T)Integer.valueOf(childElement.getTextContent()));
+ }
+ }
+ }
+
+ private static final Element getFirstElementByTagName(String name, Element element) {
+ NodeList nodeList = element.getElementsByTagName(name);
+ if (nodeList.getLength() == 0) {
+ return null;
+ }
+ return (Element)nodeList.item(0);
+ }
+}
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/package-info.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/package-info.java
index c96debb..a9f3979 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/package-info.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/package-info.java
@@ -14,5 +14,5 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@org.osgi.annotation.versioning.Version("1.3.1")
+@org.osgi.annotation.versioning.Version("1.4.0")
package org.apache.jackrabbit.vault.packaging.registry;
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/taskoption/ImportOptionsPackageTaskOption.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/taskoption/ImportOptionsPackageTaskOption.java
new file mode 100644
index 0000000..114d9bc
--- /dev/null
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/registry/taskoption/ImportOptionsPackageTaskOption.java
@@ -0,0 +1,66 @@
+/*
+ * 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.jackrabbit.vault.packaging.registry.taskoption;
+
+import org.apache.jackrabbit.vault.fs.io.ImportOptions;
+import org.apache.jackrabbit.vault.packaging.registry.PackageTaskOptions;
+
+public class ImportOptionsPackageTaskOption implements PackageTaskOptions {
+
+ private final ImportOptions importOptions;
+
+ public ImportOptionsPackageTaskOption(ImportOptions importOptions) {
+ super();
+ this.importOptions = importOptions;
+ }
+
+ public ImportOptions getImportOptions() {
+ return importOptions;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((importOptions == null) ? 0 : importOptions.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ImportOptionsPackageTaskOption other = (ImportOptionsPackageTaskOption) obj;
+ if (importOptions == null) {
+ if (other.importOptions != null)
+ return false;
+ } else if (!importOptions.equals(other.importOptions))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "ImportOptionsPackageTaskOption [" + (importOptions != null ? "importOptions=" + importOptions : "") + "]";
+ }
+
+
+}
diff --git a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/registry/impl/ExecutionPlanBuilderImplTest.java b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/registry/impl/ExecutionPlanBuilderImplTest.java
new file mode 100644
index 0000000..e5a19c1
--- /dev/null
+++ b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/registry/impl/ExecutionPlanBuilderImplTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.jackrabbit.vault.packaging.registry.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.vault.fs.api.ImportMode;
+import org.apache.jackrabbit.vault.fs.io.AccessControlHandling;
+import org.apache.jackrabbit.vault.fs.io.ImportOptions;
+import org.apache.jackrabbit.vault.packaging.PackageException;
+import org.apache.jackrabbit.vault.packaging.registry.ExecutionPlan;
+import org.apache.jackrabbit.vault.packaging.registry.PackageTask;
+import org.apache.jackrabbit.vault.packaging.registry.PackageTask.State;
+import org.apache.jackrabbit.vault.packaging.registry.PackageTask.Type;
+import org.apache.jackrabbit.vault.packaging.registry.PackageTaskOptions;
+import org.apache.jackrabbit.vault.packaging.registry.taskoption.ImportOptionsPackageTaskOption;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ExecutionPlanBuilderImplTest {
+
+ private ExecutionPlanBuilderImpl builder;
+
+ @Mock
+ private Session session;
+ @Before
+ public void setUp() {
+ builder = new ExecutionPlanBuilderImpl(new MockPackageRegistry(MockPackageRegistry.NEW_PACKAGE_ID));
+ }
+
+ @Test
+ public void testSaveAndLoad() throws IOException, PackageException {
+ ImportOptions importOptions = new ImportOptions();
+ importOptions.setStrict(true);
+ importOptions.setAccessControlHandling(AccessControlHandling.MERGE_PRESERVE);
+ importOptions.setAutoSaveThreshold(123);
+ importOptions.setCugHandling(AccessControlHandling.CLEAR);
+ importOptions.setImportMode(ImportMode.UPDATE);
+ importOptions.setDryRun(true);
+ importOptions.setNonRecursive(true);
+ PackageTaskOptions options = new ImportOptionsPackageTaskOption(importOptions);
+ builder.addTask().with(MockPackageRegistry.NEW_PACKAGE_ID).withOptions(options).with(PackageTask.Type.INSTALL);
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ builder.save(out);
+ builder = new ExecutionPlanBuilderImpl(new MockPackageRegistry(MockPackageRegistry.NEW_PACKAGE_ID));
+ builder.load(new ByteArrayInputStream(out.toByteArray()));
+ builder.with(session);
+ ExecutionPlan plan = builder.execute();
+ PackageTaskImpl expectedTask = new PackageTaskImpl(MockPackageRegistry.NEW_PACKAGE_ID, Type.INSTALL, options);
+ expectedTask.state = State.COMPLETED;
+ MatcherAssert.assertThat(plan.getTasks(), Matchers.contains(expectedTask));
+ }
+}
diff --git a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/registry/impl/MockPackageRegistry.java b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/registry/impl/MockPackageRegistry.java
index fa01eb1..9ac5795 100644
--- a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/registry/impl/MockPackageRegistry.java
+++ b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/registry/impl/MockPackageRegistry.java
@@ -118,7 +118,10 @@ public final class MockPackageRegistry implements PackageRegistry {
public @NotNull DependencyReport analyzeDependencies(@NotNull PackageId id, boolean onlyInstalled)
throws IOException, NoSuchPackageException {
if (containedPackageIdsAndDependencies.containsKey(id)) {
- return Mockito.mock(DependencyReport.class);
+ DependencyReport report = Mockito.mock(DependencyReport.class);
+ Mockito.when(report.getUnresolvedDependencies()).thenReturn(new Dependency[0]);
+ Mockito.when(report.getResolvedDependencies()).thenReturn(new PackageId[0]);
+ return report;
} else {
throw new NoSuchPackageException("Could not find package with id " + id);
}