OperationFactory { public Composite fromChangeSet(ResourceAddress address, Map<String, Object> changeSet, Metadata metadata) { Map<String, Operation> operations = new HashMap<>(); HashMap<String, Object> localChanges = new HashMap<>(changeSet); ResourceDescription resourceDescription = metadata.getDescription(); Set<String> conflicts = new HashSet<>(); Map<String, List<String>> allAlternatives = localChanges.keySet().stream() .filter(name -> { Object value = changeSet.get(name); return !isNullOrEmpty(value); }) .collect(toMap(identity(), name -> resourceDescription.findAlternatives(ATTRIBUTES, name))); allAlternatives.forEach((attribute, alternatives) -> { logger.debug("Alternatives resolution for {} -> [{}]", attribute, String.join(", ", alternatives)); HashSet<String> intersection = new HashSet<>(alternatives); intersection.retainAll(changeSet.keySet()); if (intersection.isEmpty()) { alternatives.forEach(alternative -> { boolean alternativeDoesntExist = resourceDescription.findAttribute(ATTRIBUTES, alternative) == null; if (resourceDescription.isDeprecated(ATTRIBUTES, alternative) || alternativeDoesntExist) { logger.debug("Skip undefine operations for deprecated or non-existent alternative {}", alternative); } else { logger.debug("Add undefine operations for alternative {}", alternative); operations.putIfAbsent(alternative, undefineAttribute(address, alternative)); List<String> requires = resourceDescription.findRequires(ATTRIBUTES, alternative); if (!requires.isEmpty()) { logger.debug("Add undefine operations for attributes which require {}: [{}]", alternative, String.join(", ", requires)); requires.forEach(r -> operations.putIfAbsent(r, undefineAttribute(address, r))); } } }); } else { conflicts.add(attribute); conflicts.addAll(intersection); logger.debug("Record conflict {} <-> [{}]", attribute, String.join(", ", intersection)); } alternatives.forEach(localChanges::remove); }); if (!conflicts.isEmpty()) { logger.debug("Try to resolve conflicts between alternatives [{}]", String.join(", ", conflicts)); Map<Boolean, List<String>> resolution = conflicts.stream().collect(groupingBy(conflict -> { Object value = changeSet.get(conflict); return isNullOrEmpty(value) || resourceDescription.isDefaultValue(ATTRIBUTES, conflict, value); })); List<String> undefine = resolution.getOrDefault(true, Collections.emptyList()); List<String> write = resolution.getOrDefault(false, Collections.emptyList()); if (write.size() > 1) { logger.error( "More than one conflicting alternative attribute which is not null, empty or default: [{}]. This should have been caught by a form validation. Adding the write operations anyway to get an appropriate error message from the server.", String.join(", ", write)); } logger.debug("Add undefine operations for [{}], write operation for [{}]", String.join(", ", undefine), String.join(", ", write)); undefine.forEach(u -> { operations.putIfAbsent(u, undefineAttribute(address, u)); localChanges.remove(u); List<String> requires = resourceDescription.findRequires(ATTRIBUTES, u); requires.forEach(ur -> { operations.putIfAbsent(ur, undefineAttribute(address, ur)); localChanges.remove(ur); }); }); write.forEach(w -> { operations.putIfAbsent(w, writeAttribute(address, w, changeSet.get(w), resourceDescription)); localChanges.remove(w); List<String> writeAlternatives = resourceDescription.findAlternatives(ATTRIBUTES, w); writeAlternatives.forEach(wa -> { operations.putIfAbsent(wa, undefineAttribute(address, wa)); localChanges.remove(wa); }); }); } logger.debug("Process remaining attributes [{}]", String.join(", ", localChanges.keySet())); localChanges.forEach((name, value) -> operations.putIfAbsent(name, writeAttribute(address, name, value, resourceDescription))); return new Composite(operations.values().stream().filter(Objects::nonNull).collect(toList())); } OperationFactory();  OperationFactory(Function<String, String> nameFn); Composite fromChangeSet(ResourceAddress address, Map<String, Object> changeSet,
            Metadata metadata);  }
@Test public void empty() { Composite composite = operationFactory.fromChangeSet(address, Collections.emptyMap(), metadata); assertTrue(composite.isEmpty()); }
@Test public void notInMetadata() { Composite composite = operationFactory.fromChangeSet(address, ImmutableMap.of("foo", "bar"), metadata); assertEquals(1, composite.size()); assertWrite(composite, "foo", "bar"); }
@Test public void write() { Composite composite = operationFactory.fromChangeSet(address, ImmutableMap.of("allocation-retry", 23L), metadata); assertEquals(1, composite.size()); assertWrite(composite, "allocation-retry", 23L); }
@Test public void undefine() { Composite composite = operationFactory.fromChangeSet(address, ImmutableMap.of("class-name", ""), metadata); assertEquals(1, composite.size()); assertUndefine(composite, "class-name"); }
@Test public void defaultValue() { Composite composite = operationFactory.fromChangeSet(address, ImmutableMap.of("enlistment", true), metadata); assertEquals(1, composite.size()); assertUndefine(composite, "enlistment"); }
@Test public void expression() { Composite composite = operationFactory.fromChangeSet(address, ImmutableMap.of("expression", "${foo:bar}"), metadata); assertEquals(1, composite.size()); assertWrite(composite, "expression", "${foo:bar}"); }
@Test public void mixed() { Composite composite = operationFactory.fromChangeSet(address, ImmutableMap.of("class-name", "", "jndi-name", "java:/foo"), metadata); assertEquals(2, composite.size()); assertUndefine(composite, "class-name"); assertWrite(composite, "jndi-name", "java:/foo"); }
@Test public void alternativesNoConflicts() { Composite composite = operationFactory.fromChangeSet(address, ImmutableMap.of("authentication-context", "foo"), metadata); assertEquals(2, composite.size()); assertUndefine(composite, "authentication-context-and-application"); assertWrite(composite, "authentication-context", "foo"); }
@Test public void alternativesNoConflictsWithRequires() { Composite composite = operationFactory.fromChangeSet(address, ImmutableMap.of("security-domain", "foo"), metadata); assertEquals(6, composite.size()); assertUndefine(composite, "security-application"); assertUndefine(composite, "security-domain-and-application"); assertUndefine(composite, "elytron-enabled"); assertUndefine(composite, "authentication-context"); assertUndefine(composite, "authentication-context-and-application"); assertWrite(composite, "security-domain", "foo"); }
@Test public void alternativesWithConflicts1() { Composite composite = operationFactory.fromChangeSet(address, ImmutableMap.of("elytron-enabled", true, "authentication-context", "foo"), metadata); assertEquals(6, composite.size()); assertUndefine(composite, "security-application"); assertUndefine(composite, "security-domain"); assertUndefine(composite, "security-domain-and-application"); assertUndefine(composite, "authentication-context-and-application"); assertWrite(composite, "elytron-enabled", true); assertWrite(composite, "authentication-context", "foo"); }
@Test public void alternativesWithConflicts2() { Composite composite = operationFactory.fromChangeSet(address, ImmutableMap.of("elytron-enabled", false, "security-domain", "foo"), metadata); assertEquals(6, composite.size()); assertUndefine(composite, "security-application"); assertUndefine(composite, "security-domain-and-application"); assertUndefine(composite, "elytron-enabled"); assertUndefine(composite, "authentication-context"); assertUndefine(composite, "authentication-context-and-application"); assertWrite(composite, "security-domain", "foo"); }