Search in sources :

Example 1 with ResourceDescription

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();
}
Also used : AddressTemplate(org.jboss.hal.meta.AddressTemplate) ResourceDescription(org.jboss.hal.meta.description.ResourceDescription) Capabilities(org.jboss.hal.meta.capabilitiy.Capabilities) Metadata(org.jboss.hal.meta.Metadata) ModelNode(org.jboss.hal.dmr.ModelNode) ExternalModelNode(org.jboss.hal.dmr.ExternalModelNode) Before(org.junit.Before)

Example 2 with ResourceDescription

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);
                }
            }
        }
    }
}
Also used : ResourceDescription(org.jboss.hal.meta.description.ResourceDescription) ResourceAddress(org.jboss.hal.dmr.ResourceAddress) SecurityContext(org.jboss.hal.meta.security.SecurityContext) ModelNode(org.jboss.hal.dmr.ModelNode) Property(org.jboss.hal.dmr.Property)

Example 3 with ResourceDescription

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);
}
Also used : ResourceDescription(org.jboss.hal.meta.description.ResourceDescription) StaticResourceDescription(org.jboss.hal.meta.description.StaticResourceDescription) SecurityContext(org.jboss.hal.meta.security.SecurityContext) ModelNode(org.jboss.hal.dmr.ModelNode) JsIgnore(jsinterop.annotations.JsIgnore)

Example 4 with ResourceDescription

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);
}
Also used : ResourceDescription(org.jboss.hal.meta.description.ResourceDescription) StaticResourceDescription(org.jboss.hal.meta.description.StaticResourceDescription) SecurityContext(org.jboss.hal.meta.security.SecurityContext) ModelNode(org.jboss.hal.dmr.ModelNode) JsProperty(jsinterop.annotations.JsProperty) Property(org.jboss.hal.dmr.Property) JsIgnore(jsinterop.annotations.JsIgnore)

Example 5 with ResourceDescription

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()));
}
Also used : ModelNode(org.jboss.hal.dmr.ModelNode) DEFAULT(org.jboss.hal.dmr.ModelDescriptionConstants.DEFAULT) TYPE(org.jboss.hal.dmr.ModelDescriptionConstants.TYPE) VALUE_TYPE(org.jboss.hal.dmr.ModelDescriptionConstants.VALUE_TYPE) LoggerFactory(org.slf4j.LoggerFactory) Collectors.groupingBy(java.util.stream.Collectors.groupingBy) HashMap(java.util.HashMap) Function(java.util.function.Function) ResourceAddress(org.jboss.hal.dmr.ResourceAddress) TreeSet(java.util.TreeSet) ArrayList(java.util.ArrayList) ModelType(org.jboss.hal.dmr.ModelType) HashSet(java.util.HashSet) BigDecimal(java.math.BigDecimal) Property(org.jboss.hal.dmr.Property) ResourceDescription(org.jboss.hal.meta.description.ResourceDescription) Strings(com.google.common.base.Strings) Collectors.toMap(java.util.stream.Collectors.toMap) VALUE(org.jboss.hal.dmr.ModelDescriptionConstants.VALUE) Map(java.util.Map) Expression(org.jboss.hal.core.expression.Expression) NAME(org.jboss.hal.dmr.ModelDescriptionConstants.NAME) UNDEFINE_ATTRIBUTE_OPERATION(org.jboss.hal.dmr.ModelDescriptionConstants.UNDEFINE_ATTRIBUTE_OPERATION) BigInteger(java.math.BigInteger) EXPRESSIONS_ALLOWED(org.jboss.hal.dmr.ModelDescriptionConstants.EXPRESSIONS_ALLOWED) Metadata(org.jboss.hal.meta.Metadata) Logger(org.slf4j.Logger) ACCESS_TYPE(org.jboss.hal.dmr.ModelDescriptionConstants.ACCESS_TYPE) READ_ONLY(org.jboss.hal.dmr.ModelDescriptionConstants.READ_ONLY) Operation(org.jboss.hal.dmr.Operation) ModelNodeHelper.failSafeList(org.jboss.hal.dmr.ModelNodeHelper.failSafeList) ALTERNATIVES(org.jboss.hal.dmr.ModelDescriptionConstants.ALTERNATIVES) Set(java.util.Set) WRITE_ATTRIBUTE_OPERATION(org.jboss.hal.dmr.ModelDescriptionConstants.WRITE_ATTRIBUTE_OPERATION) NILLABLE(org.jboss.hal.dmr.ModelDescriptionConstants.NILLABLE) Objects(java.util.Objects) Composite(org.jboss.hal.dmr.Composite) List(java.util.List) Collectors.toList(java.util.stream.Collectors.toList) ATTRIBUTES(org.jboss.hal.dmr.ModelDescriptionConstants.ATTRIBUTES) Function.identity(java.util.function.Function.identity) Collections(java.util.Collections) REQUIRES(org.jboss.hal.dmr.ModelDescriptionConstants.REQUIRES) Composite(org.jboss.hal.dmr.Composite) HashMap(java.util.HashMap) Operation(org.jboss.hal.dmr.Operation) ResourceDescription(org.jboss.hal.meta.description.ResourceDescription) Objects(java.util.Objects) ArrayList(java.util.ArrayList) ModelNodeHelper.failSafeList(org.jboss.hal.dmr.ModelNodeHelper.failSafeList) List(java.util.List) Collectors.toList(java.util.stream.Collectors.toList) HashSet(java.util.HashSet)

Aggregations

ResourceDescription (org.jboss.hal.meta.description.ResourceDescription)10 ModelNode (org.jboss.hal.dmr.ModelNode)7 SecurityContext (org.jboss.hal.meta.security.SecurityContext)6 ResourceAddress (org.jboss.hal.dmr.ResourceAddress)5 Map (java.util.Map)4 Property (org.jboss.hal.dmr.Property)3 Metadata (org.jboss.hal.meta.Metadata)3 ArrayList (java.util.ArrayList)2 HashSet (java.util.HashSet)2 TreeSet (java.util.TreeSet)2 JsIgnore (jsinterop.annotations.JsIgnore)2 Composite (org.jboss.hal.dmr.Composite)2 ModelType (org.jboss.hal.dmr.ModelType)2 Operation (org.jboss.hal.dmr.Operation)2 StaticResourceDescription (org.jboss.hal.meta.description.StaticResourceDescription)2 Stopwatch (com.google.common.base.Stopwatch)1 Strings (com.google.common.base.Strings)1 BigDecimal (java.math.BigDecimal)1 BigInteger (java.math.BigInteger)1 Collections (java.util.Collections)1