use of org.jboss.hal.meta.description.ResourceDescription in project console by hal.
the class OperationFactoryTest method setUp.
@Before
public void setUp() {
AddressTemplate template = AddressTemplate.of("/{selected.profile}/subsystem=resource-adapters/resource-adapter=*/connection-definitions=*");
ModelNode rrd = ExternalModelNode.read(OperationFactoryTest.class.getResourceAsStream("connection-definition.dmr"));
metadata = new Metadata(template, () -> SecurityContext.RWX, new ResourceDescription(rrd), new Capabilities(null));
address = ResourceAddress.root();
operationFactory = new OperationFactory();
}
use of org.jboss.hal.meta.description.ResourceDescription in project console by hal.
the class SingleRrdParser method parseSingle.
private void parseSingle(ResourceAddress address, ModelNode modelNode) {
// resource description
// to reduce the payload we only use the flat model node w/o children
ModelNode childrenNode = modelNode.hasDefined(CHILDREN) ? modelNode.remove(CHILDREN) : new ModelNode();
if (!rrdResult.containsResourceDescription(address) && modelNode.hasDefined(DESCRIPTION)) {
rrdResult.addResourceDescription(addressProcessor.apply(address), new ResourceDescription(modelNode));
}
// security context
ModelNode accessControl = modelNode.get(ACCESS_CONTROL);
if (accessControl.isDefined()) {
if (!rrdResult.containsSecurityContext(address) && accessControl.hasDefined(DEFAULT)) {
rrdResult.addSecurityContext(address, new SecurityContext(accessControl.get(DEFAULT)));
}
// exceptions
if (accessControl.hasDefined(EXCEPTIONS)) {
List<Property> exceptions = accessControl.get(EXCEPTIONS).asPropertyList();
for (Property property : exceptions) {
ModelNode exception = property.getValue();
ResourceAddress exceptionAddress = new ResourceAddress(exception.get(ADDRESS));
if (!rrdResult.containsSecurityContext(exceptionAddress)) {
rrdResult.addSecurityContext(exceptionAddress, new SecurityContext(exception));
}
}
}
}
// children
if (childrenNode.isDefined()) {
List<Property> children = childrenNode.asPropertyList();
for (Property child : children) {
String addressKey = child.getName();
if (child.getValue().hasDefined(MODEL_DESCRIPTION)) {
List<Property> modelDescriptions = child.getValue().get(MODEL_DESCRIPTION).asPropertyList();
for (Property modelDescription : modelDescriptions) {
String addressValue = modelDescription.getName();
ModelNode childNode = modelDescription.getValue();
ResourceAddress childAddress = new ResourceAddress(address).add(addressKey, addressValue);
parseSingle(childAddress, childNode);
}
}
}
}
}
use of org.jboss.hal.meta.description.ResourceDescription in project console by hal.
the class Metadata method forOperation.
@JsIgnore
public Metadata forOperation(String name) {
ModelNode payload = new ModelNode();
payload.get(DESCRIPTION).set(failSafeGet(description, OPERATIONS + "/" + name + "/" + DESCRIPTION));
payload.get(ATTRIBUTES).set(failSafeGet(description, OPERATIONS + "/" + name + "/" + REQUEST_PROPERTIES));
SecurityContext parentContext = this.securityContext.get();
SecurityContext operationContext = new SecurityContext(new ModelNode()) {
@Override
public boolean isReadable() {
return parentContext.isExecutable(name);
}
@Override
public boolean isWritable() {
return parentContext.isExecutable(name);
}
@Override
public boolean isReadable(String attribute) {
// if the operation is executable all of its request properties are readable as well
return isReadable();
}
@Override
public boolean isWritable(String attribute) {
// if the operation is executable all of its request properties are writable as well
return isWritable();
}
@Override
public boolean isExecutable(String operation) {
return parentContext.isExecutable(operation);
}
};
return new Metadata(template, () -> operationContext, new ResourceDescription(payload), capabilities);
}
use of org.jboss.hal.meta.description.ResourceDescription in project console by hal.
the class Metadata method forComplexAttribute.
/**
* Creates a new metadata instance based on this metadata with the attributes taken from the specified complex attribute.
* The resource description will only include the attributes but no operations!
*
* @param prefixLabel if {@code true} the labels of the attributes of the complex attribute are prefixed with name of the
* complex attribute.
*/
@JsIgnore
public Metadata forComplexAttribute(String name, boolean prefixLabel) {
ModelNode payload = new ModelNode();
payload.get(DESCRIPTION).set(failSafeGet(description, ATTRIBUTES + "/" + name + "/" + DESCRIPTION));
payload.get(REQUIRED).set(failSafeGet(description, ATTRIBUTES + "/" + name + "/" + REQUIRED));
payload.get(NILLABLE).set(failSafeGet(description, ATTRIBUTES + "/" + name + "/" + NILLABLE));
Property complexAttribute = description.findAttribute(ATTRIBUTES, name);
if (complexAttribute != null && complexAttribute.getValue().hasDefined(VALUE_TYPE)) {
complexAttribute.getValue().get(VALUE_TYPE).asPropertyList().forEach(nestedProperty -> {
// The nested name is *always* just the nested property name,
// since it's used when building the DMR operations
String nestedName = nestedProperty.getName();
ModelNode nestedDescription = nestedProperty.getValue();
// up by LabelBuilder.label(Property)
if (prefixLabel) {
nestedDescription.get(HAL_LABEL).set(name + "-" + nestedProperty.getName());
}
payload.get(ATTRIBUTES).get(nestedName).set(nestedDescription);
});
}
SecurityContext parentContext = this.securityContext.get();
SecurityContext attributeContext = new SecurityContext(new ModelNode()) {
@Override
public boolean isReadable() {
return parentContext.isReadable(name);
}
@Override
public boolean isWritable() {
return parentContext.isWritable(name);
}
@Override
public boolean isReadable(String attribute) {
// if the complex attribute is readable all nested attributes are readable as well
return isReadable();
}
@Override
public boolean isWritable(String attribute) {
// if the complex attribute is writable all nested attributes are writable as well
return isWritable();
}
@Override
public boolean isExecutable(String operation) {
return parentContext.isExecutable(operation);
}
};
return new Metadata(template, () -> attributeContext, new ResourceDescription(payload), capabilities);
}
use of org.jboss.hal.meta.description.ResourceDescription in project console by hal.
the class OperationFactory method fromChangeSet.
/**
* Turns a change-set into a composite operation containing
* {@linkplain org.jboss.hal.dmr.ModelDescriptionConstants#WRITE_ATTRIBUTE_OPERATION write-attribute} and
* {@linkplain org.jboss.hal.dmr.ModelDescriptionConstants#UNDEFINE_ATTRIBUTE_OPERATION undefine-attribute} operations.
* <p>
* The composite operation will contain {@linkplain org.jboss.hal.dmr.ModelDescriptionConstants#UNDEFINE_ATTRIBUTE_OPERATION
* undefine-attribute} operations which reflect the alternative attributes as defined in the specified metadata.
*
* @param address the fq address used for the operations
* @param changeSet the changed values
* @param metadata the metadata which should contain the attribute definitions of the change-set
*/
public Composite fromChangeSet(ResourceAddress address, Map<String, Object> changeSet, Metadata metadata) {
// TODO Is it safe to always use ATTRIBUTES as path when calling ResourceDescription methods?
Map<String, Operation> operations = new HashMap<>();
HashMap<String, Object> localChanges = new HashMap<>(changeSet);
ResourceDescription resourceDescription = metadata.getDescription();
// look for alternatives
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()) {
// the easy part: no conflicts
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 {
// possible conflicts: one or more alternatives are also in the change-set
// just collect for now and resolve later
conflicts.add(attribute);
conflicts.addAll(intersection);
logger.debug("Record conflict {} <-> [{}]", attribute, String.join(", ", intersection));
}
alternatives.forEach(localChanges::remove);
});
if (!conflicts.isEmpty()) {
// try to resolve conflicts: only one of the conflicting attributes must have a value other than
// null, empty or default
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);
// process requires of the current undefine attribute
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, true));
localChanges.remove(w);
List<String> writeAlternatives = resourceDescription.findAlternatives(ATTRIBUTES, w);
// process alternatives of the current write attribute
writeAlternatives.forEach(wa -> {
operations.putIfAbsent(wa, undefineAttribute(address, wa));
localChanges.remove(wa);
});
});
}
// handle the remaining attributes
logger.debug("Process remaining attributes [{}]", String.join(", ", localChanges.keySet()));
localChanges.forEach((name, value) -> operations.putIfAbsent(name, writeAttribute(address, name, value, resourceDescription, false)));
return new Composite(operations.values().stream().filter(Objects::nonNull).collect(toList()));
}
Aggregations