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 2020/07/03 15:17:21 UTC
[jackrabbit-filevault] branch master updated: JCRVLT-449 various
fixes for RCP task serialization/deserialization
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 917660d JCRVLT-449 various fixes for RCP task serialization/deserialization
917660d is described below
commit 917660d0076b8be0a11b4f226dde798842128646
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Fri Jul 3 17:17:10 2020 +0200
JCRVLT-449 various fixes for RCP task serialization/deserialization
---
.../vault/rcp/impl/RcpTaskManagerImpl.java | 62 ++++++++++++++++------
.../vault/rcp/impl/RcpTaskManagerImplTest.java | 12 +++--
2 files changed, 54 insertions(+), 20 deletions(-)
diff --git a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImpl.java b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImpl.java
index 03b942e..74caf67 100644
--- a/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImpl.java
+++ b/vault-rcp/src/main/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImpl.java
@@ -28,6 +28,8 @@ import java.util.Map;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import javax.jcr.Credentials;
import javax.jcr.RepositoryException;
@@ -46,6 +48,7 @@ import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.propertytypes.ServiceVendor;
import org.osgi.service.metatype.annotations.AttributeDefinition;
@@ -90,10 +93,12 @@ public class RcpTaskManagerImpl implements RcpTaskManager {
private final Configuration configuration;
+ /** the serialized tasks which have been processed (for detecting relevant updates) */
+ private String serializedTasks;
@Activate
public RcpTaskManagerImpl(BundleContext bundleContext, @Reference DynamicClassLoaderManager dynLoaderMgr,
- @Reference ConfigurationAdmin configurationAdmin) {
+ @Reference ConfigurationAdmin configurationAdmin, Map <String, Object> newConfigProperties) {
mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
mapper.addMixIn(RepositoryAddress.class, RepositoryAddressMixin.class);
SimpleModule module = new SimpleModule();
@@ -107,7 +112,7 @@ public class RcpTaskManagerImpl implements RcpTaskManager {
Configuration configuration;
try {
configuration = configurationAdmin.getConfiguration(PID);
- tasks = loadTasks(configuration.getProperties(), dataFile);
+ tasks = loadTasks((String)newConfigProperties.get(PROP_TASKS_SERIALIZATION), dataFile);
} catch (IOException e) {
log.error("Could not restore previous tasks", e);
configuration = null;
@@ -123,38 +128,53 @@ public class RcpTaskManagerImpl implements RcpTaskManager {
}
log.info("RcpTaskManager deactivated. Stopping running tasks...done.");
}
-
- private void persistTasks() {
- Dictionary<String, Object> configProperties = new Hashtable<>();
- try {
- persistTasks(configProperties, dataFile);
- configuration.update(configProperties);
- log.info("Persisted RCP tasks in OSGi configuration");
- } catch (RepositoryException | IOException e) {
- throw new IllegalStateException("Could not persist tasks", e);
+
+ @Modified
+ void modified(Map <String, Object> newConfigProperties) throws IOException {
+ // might be triggered internally or externally
+ // only external events are relevant
+ if (!serializedTasks.equals(newConfigProperties.get(PROP_TASKS_SERIALIZATION))) {
+ log.info("Detected external properties change");
+ tasks = loadTasks((String) newConfigProperties.get(PROP_TASKS_SERIALIZATION), null);
}
}
- private SortedMap<String, RcpTaskImpl> loadTasks(Dictionary<String, Object> configProperties, File dataFile) throws IOException {
- if (configProperties == null) {
+ static Map<String, Object> createMapFromDictionary(Dictionary<String, Object> dictionary) {
+ // filter out irrelevant properties
+ List<String> keys = Collections.list(dictionary.keys());
+ return keys.stream().collect(Collectors.toMap(Function.identity(), dictionary::get));
+ }
+
+ private SortedMap<String, RcpTaskImpl> loadTasks(String serializedTasks, File dataFile) throws IOException {
+ if (serializedTasks != null && serializedTasks.isEmpty()) {
log.info("No previously persisted tasks found in OSGi configuation");
return new TreeMap<>();
}
- String serializedTasks = (String) configProperties.get(PROP_TASKS_SERIALIZATION);
if (serializedTasks == null) {
log.info("No previously persisted tasks found in OSGi configuation");
return new TreeMap<>();
}
SortedMap<String, RcpTaskImpl> tasks = mapper.readValue(serializedTasks, new TypeReference<SortedMap<String, RcpTaskImpl>>() {});
+ validateTasks(tasks);
// additionally load credentials data from bundle context
if (dataFile != null && dataFile.exists()) {
loadTasksCredentials(tasks, dataFile);
} else {
log.info("No previously persisted task credentials found at '{}'", dataFile);
}
+ this.serializedTasks = serializedTasks;
return tasks;
}
+ void validateTasks(SortedMap<String, RcpTaskImpl> tasks) {
+ for (Map.Entry<String, RcpTaskImpl> entry : tasks.entrySet()) {
+ // make sure id of map entry is task id
+ if (!entry.getKey().equals(entry.getValue().getId())) {
+ throw new IllegalArgumentException("Id of entry " + entry.getKey() + " does not match its task id " + entry.getValue().getId());
+ }
+ }
+ }
+
private void loadTasksCredentials(Map<String, RcpTaskImpl> tasks, File dataFile) throws IOException {
Properties props = new Properties();
try (FileInputStream inputStream = new FileInputStream(dataFile)) {
@@ -169,8 +189,19 @@ public class RcpTaskManagerImpl implements RcpTaskManager {
}
}
+ private void persistTasks() {
+ Dictionary<String, Object> configProperties = new Hashtable<>();
+ try {
+ persistTasks(configProperties, dataFile);
+ configuration.updateIfDifferent(configProperties);
+ log.info("Persisted RCP tasks in OSGi configuration");
+ } catch (RepositoryException | IOException e) {
+ throw new IllegalStateException("Could not persist tasks", e);
+ }
+ }
+
private void persistTasks(Dictionary<String, Object> configProperties, File dataFile) throws RepositoryException, JsonGenerationException, JsonMappingException, IOException {
- String serializedTasks = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(tasks);
+ serializedTasks = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(tasks);
configProperties.put(PROP_TASKS_SERIALIZATION, serializedTasks);
// additionally persist the sensitive data in a data file
@@ -229,6 +260,7 @@ public class RcpTaskManagerImpl implements RcpTaskManager {
RcpTask rcpTask = tasks.remove(taskId);
if (rcpTask != null) {
rcpTask.stop();
+ persistTasks();
return true;
}
return false;
diff --git a/vault-rcp/src/test/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImplTest.java b/vault-rcp/src/test/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImplTest.java
index 1c27341..68b919d 100644
--- a/vault-rcp/src/test/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImplTest.java
+++ b/vault-rcp/src/test/java/org/apache/jackrabbit/vault/rcp/impl/RcpTaskManagerImplTest.java
@@ -22,6 +22,7 @@ import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Dictionary;
import java.util.stream.Collectors;
@@ -71,7 +72,7 @@ public class RcpTaskManagerImplTest {
@Mock
Configuration mockConfiguration;
- Dictionary configProperties;
+ Dictionary<String, Object> configProperties;
@Rule
public TemporaryFolder folder= new TemporaryFolder();
@@ -95,8 +96,8 @@ public class RcpTaskManagerImplTest {
return null;
}
- }).when(mockConfiguration).update(Mockito.any());
- RcpTaskManagerImpl taskManager = new RcpTaskManagerImpl(mockBundleContext, mockClassLoaderManager, mockConfigurationAdmin);
+ }).when(mockConfiguration).updateIfDifferent(Mockito.any());
+ RcpTaskManagerImpl taskManager = new RcpTaskManagerImpl(mockBundleContext, mockClassLoaderManager, mockConfigurationAdmin, Collections.emptyMap());
DefaultWorkspaceFilter filter = new DefaultWorkspaceFilter();
try (InputStream input = this.getClass().getResourceAsStream("/filter.xml")) {
filter.load(input);
@@ -104,8 +105,9 @@ public class RcpTaskManagerImplTest {
taskManager.addTask(new RepositoryAddress("http://localhost:4502"), new SimpleCredentials("testUser", "pw".toCharArray()), "/target/path", "2", Arrays.asList("exclude1", "exclude2"), false);
taskManager.addTask(new RepositoryAddress("http://localhost:8080"), new SimpleCredentials("testUser3", "pw3".toCharArray()), "/target/path5", "3", filter, true);
taskManager.deactivate();
- Mockito.when(mockConfiguration.getProperties()).thenReturn(configProperties);
- RcpTaskManagerImpl taskManager2 = new RcpTaskManagerImpl(mockBundleContext, mockClassLoaderManager, mockConfigurationAdmin);
+ Assert.assertNotNull("The tasks should have been persisted here but are not!", configProperties);
+ // convert to Map
+ RcpTaskManagerImpl taskManager2 = new RcpTaskManagerImpl(mockBundleContext, mockClassLoaderManager, mockConfigurationAdmin, RcpTaskManagerImpl.createMapFromDictionary(configProperties));
// how to get list ordered by id?
Assert.assertThat(taskManager.tasks.values(), new TaskCollectionMatcher(taskManager2.tasks.values()));
}