/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.controller.operations.global;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ABSOLUTE_ADDRESS;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FILTERED_ATTRIBUTES;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FILTERED_CHILDREN_TYPES;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RELATIVE_ADDRESS;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.UNREADABLE_CHILDREN;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;
/**
* Collection point for information about data filtered from a :read-resource[-description] call.
*
* @author Brian Stansberry (c) 2013 Red Hat Inc.
*/
class FilteredData {
private final int baseAddressLength;
private Map<PathAddress, ResourceData> map;
FilteredData(PathAddress baseAddress) {
this.baseAddressLength = baseAddress.size();
}
void addReadRestrictedAttribute(PathAddress fullAddress, String attribute) {
ResourceData rd = getResourceData(fullAddress);
if (rd.attributes == null) {
rd.attributes = new HashSet<String>();
}
rd.attributes.add(attribute);
}
void addReadRestrictedResource(PathAddress fullAddress) {
assert fullAddress.size() > 0 : "cannot filter root resource";
ResourceData rd = getResourceData(fullAddress.subAddress(0, fullAddress.size() - 1));
if (rd.children == null) {
rd.children = new HashSet<PathElement>();
}
rd.children.add(fullAddress.getLastElement());
}
void addAccessRestrictedResource(PathAddress fullAddress) {
assert fullAddress.size() > 0 : "cannot filter root resource";
ResourceData rd = getResourceData(fullAddress.subAddress(0, fullAddress.size() - 1));
if (rd.childTypes == null) {
rd.childTypes = new HashSet<PathElement>();
}
rd.childTypes.add(fullAddress.getLastElement());
}
boolean hasFilteredData() {
return map != null;
}
boolean isFilteredResource(PathAddress parent, PathElement child) {
boolean result = false;
ResourceData rd = map == null ? null : map.get(parent);
if (rd != null) {
result = (rd.children != null && rd.children.contains(child))
|| (rd.childTypes != null && rd.childTypes.contains(child));
}
return result;
}
boolean isAddressFiltered(PathAddress parent, PathElement child) {
boolean result = false;
ResourceData rd = map == null ? null : map.get(parent);
if (rd != null) {
result = (rd.childTypes != null && rd.childTypes.contains(child));
}
return result;
}
/** Report on the filtered data in DMR . */
ModelNode toModelNode() {
ModelNode result = null;
if (map != null) {
result = new ModelNode();
for (Map.Entry<PathAddress, ResourceData> entry : map.entrySet()) {
ModelNode item = new ModelNode();
PathAddress pa = entry.getKey();
item.get(ABSOLUTE_ADDRESS).set(pa.toModelNode());
ResourceData rd = entry.getValue();
item.get(RELATIVE_ADDRESS).set(pa.subAddress(baseAddressLength).toModelNode());
ModelNode attrs = new ModelNode().setEmptyList();
if (rd.attributes != null) {
for (String attr : rd.attributes) {
attrs.add(attr);
}
}
if (attrs.asInt() > 0) {
item.get(FILTERED_ATTRIBUTES).set(attrs);
}
ModelNode children = new ModelNode().setEmptyList();
if (rd.children != null) {
for (PathElement pe : rd.children) {
children.add(new Property(pe.getKey(), new ModelNode(pe.getValue())));
}
}
if (children.asInt() > 0) {
item.get(UNREADABLE_CHILDREN).set(children);
}
ModelNode childTypes = new ModelNode().setEmptyList();
if (rd.childTypes != null) {
Set<String> added = new HashSet<String>();
for (PathElement pe : rd.childTypes) {
if (added.add(pe.getKey())) {
childTypes.add(pe.getKey());
}
}
}
if (childTypes.asInt() > 0) {
item.get(FILTERED_CHILDREN_TYPES).set(childTypes);
}
result.add(item);
}
}
return result;
}
/**
* Take data exported via {@link #toModelNode()} and store it locally. This is so filtering
* information from a remote process can be incorporated with local data.
*
* @param modelNode a defined node of type LIST
* @param addressPrefix address that should be added as a prefix to absolute addresses in {@code modelNode}
*/
void populate(ModelNode modelNode, PathAddress addressPrefix) {
for (ModelNode item : modelNode.asList()) {
PathAddress absAddr = addressPrefix.append(PathAddress.pathAddress(item.get(ABSOLUTE_ADDRESS)));
if (item.hasDefined(FILTERED_ATTRIBUTES)) {
for (ModelNode node : item.get(FILTERED_ATTRIBUTES).asList()) {
addReadRestrictedAttribute(absAddr, node.asString());
}
}
if (item.hasDefined(UNREADABLE_CHILDREN)) {
for (Property prop : item.get(UNREADABLE_CHILDREN).asPropertyList()) {
PathElement pe = PathElement.pathElement(prop.getName(), prop.getValue().asString());
addReadRestrictedResource(PathAddress.pathAddress(absAddr, pe));
}
}
if (item.hasDefined(FILTERED_CHILDREN_TYPES)) {
for (ModelNode type : item.get(FILTERED_CHILDREN_TYPES).asList()) {
PathElement pe = PathElement.pathElement(type.asString());
addAccessRestrictedResource(PathAddress.pathAddress(absAddr, pe));
}
}
}
}
private ResourceData getResourceData(PathAddress fullAddress) {
if (map == null) {
map = new LinkedHashMap<PathAddress, ResourceData>();
}
ResourceData result = map.get(fullAddress);
if (result == null) {
result = new ResourceData();
map.put(fullAddress, result);
}
return result;
}
private static class ResourceData {
private Set<String> attributes;
private Set<PathElement> children;
private Set<PathElement> childTypes;
}
}